diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index d7105d15..4d083eed 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @justinpolygon @penelopus @davidwf-polygonio +* @justinpolygon @suever @kschoche @lukeoleson @mmoghaddam385 @jbonzo diff --git a/massive/rest/base.py b/massive/rest/base.py index 66c28924..3349d7ef 100644 --- a/massive/rest/base.py +++ b/massive/rest/base.py @@ -68,6 +68,9 @@ def __init__( backoff_factor=0.1, # [0.0s, 0.2s, 0.4s, 0.8s, 1.6s, ...] ) + # https://urllib3.readthedocs.io/en/stable/reference/urllib3.util.html#urllib3.util.Timeout + self.timeout = urllib3.Timeout(connect=connect_timeout, read=read_timeout) + # https://urllib3.readthedocs.io/en/stable/reference/urllib3.poolmanager.html # https://urllib3.readthedocs.io/en/stable/reference/urllib3.connectionpool.html#urllib3.HTTPConnectionPool self.client = urllib3.PoolManager( @@ -76,10 +79,9 @@ def __init__( ca_certs=certifi.where(), cert_reqs="CERT_REQUIRED", retries=retry_strategy, # use the customized Retry instance + timeout=self.timeout, # set timeout for each request ) - self.timeout = urllib3.Timeout(connect=connect_timeout, read=read_timeout) - if verbose: logger.setLevel(logging.DEBUG) self.trace = trace diff --git a/massive/rest/benzinga.py b/massive/rest/benzinga.py index b3cb39ec..fdd9d0b0 100644 --- a/massive/rest/benzinga.py +++ b/massive/rest/benzinga.py @@ -12,6 +12,7 @@ BenzingaGuidance, BenzingaNews, BenzingaRating, + BenzingaBullsBearsSay, ) from .models.common import Sort from .models.request import RequestOptionBuilder @@ -479,3 +480,42 @@ def list_benzinga_ratings( deserializer=BenzingaRating.from_dict, options=options, ) + + def list_benzinga_bulls_bears_say( + self, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + benzinga_id: Optional[str] = None, + benzinga_id_any_of: Optional[str] = None, + benzinga_id_gt: Optional[str] = None, + benzinga_id_gte: Optional[str] = None, + benzinga_id_lt: Optional[str] = None, + benzinga_id_lte: Optional[str] = None, + last_updated: Optional[str] = None, + last_updated_gt: Optional[str] = None, + last_updated_gte: Optional[str] = None, + last_updated_lt: Optional[str] = None, + last_updated_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[BenzingaBullsBearsSay], HTTPResponse]: + """ + Endpoint: GET /benzinga/v1/bulls-bears-say + + A comprehensive database of analyst bull and bear case summaries for publicly traded companies, providing concise summaries of both bullish and bearish investment arguments to help investors see both sides of the story before making investment decisions. + """ + url = "/benzinga/v1/bulls-bears-say" + return self._paginate( + path=url, + params=self._get_params(self.list_benzinga_bulls_bears_say, locals()), + raw=raw, + deserializer=BenzingaBullsBearsSay.from_dict, + options=options, + ) diff --git a/massive/rest/economy.py b/massive/rest/economy.py index 032791c1..4c4b251f 100644 --- a/massive/rest/economy.py +++ b/massive/rest/economy.py @@ -7,6 +7,9 @@ FedInflation, TreasuryYield, FedInflationExpectations, + FedLaborMarket, + EUMerchantAggregate, + EUMerchantHierarchy, ) from .models.common import Sort, Order from .models.request import RequestOptionBuilder @@ -127,3 +130,143 @@ def list_inflation_expectations( result_key="results", options=options, ) + + def list_labor_market_indicators( + self, + date: Optional[str] = None, + date_any_of: Optional[str] = None, + date_gt: Optional[str] = None, + date_gte: Optional[str] = None, + date_lt: Optional[str] = None, + date_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[str] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[FedLaborMarket], HTTPResponse]: + """ + Labor market indicators from the Federal Reserve, including unemployment rate, labor force participation, average hourly earnings, and job openings data. + + :param date: Calendar date of the observation (YYYY-MM-DD). + :param date_any_of: Filter equal to any of the values. Multiple values can be specified by using a comma separated list. + :param date_gt: Filter greater than the value. + :param date_gte: Filter greater than or equal to the value. + :param date_lt: Filter less than the value. + :param date_lte: Filter less than or equal to the value. + :param limit: Limit the maximum number of results returned. Defaults to '100' if not specified. The maximum allowed limit is '50000'. + :param sort: A comma separated list of sort columns. For each column, append '.asc' or '.desc' to specify the sort direction. The sort column defaults to 'date' if not specified. The sort order defaults to 'asc' if not specified. + :param params: Additional query parameters. + :param raw: Return raw HTTPResponse object if True, else return Iterator[FedLaborMarket]. + :param options: RequestOptionBuilder for additional headers or params. + :return: An iterator of FedLaborMarket objects or HTTPResponse if raw=True. + """ + url = "/fed/v1/labor-market" + + return self._paginate( + path=url, + params=self._get_params(self.list_labor_market_indicators, locals()), + deserializer=FedLaborMarket.from_dict, + raw=raw, + options=options, + ) + + def list_eu_merchant_aggregates( + self, + transaction_date: Optional[Union[str, date]] = None, + transaction_date_gt: Optional[Union[str, date]] = None, + transaction_date_gte: Optional[Union[str, date]] = None, + transaction_date_lt: Optional[Union[str, date]] = None, + transaction_date_lte: Optional[Union[str, date]] = None, + name: Optional[str] = None, + name_any_of: Optional[str] = None, + name_gt: Optional[str] = None, + name_gte: Optional[str] = None, + name_lt: Optional[str] = None, + name_lte: Optional[str] = None, + user_country: Optional[str] = None, + user_country_any_of: Optional[str] = None, + channel: Optional[str] = None, + channel_any_of: Optional[str] = None, + consumer_type: Optional[str] = None, + consumer_type_any_of: Optional[str] = None, + parent_name: Optional[str] = None, + parent_name_any_of: Optional[str] = None, + parent_name_gt: Optional[str] = None, + parent_name_gte: Optional[str] = None, + parent_name_lt: Optional[str] = None, + parent_name_lte: Optional[str] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[EUMerchantAggregate], HTTPResponse]: + """ + Aggregated consumer transactions from European credit card panels (UK, DE, FR, IT, ES, AT). + Each row represents daily credit card, debit card, or open banking transactions + (7-day lag from transaction date) at a tagged merchant or payment processor. + + Includes ticker (Bloomberg) and industry mapping for ~250 US public companies. + User counts provided across 8- and 28-day windows for normalization. + """ + url = "/consumer-spending/eu/v1/merchant-aggregates" + + return self._paginate( + path=url, + params=self._get_params(self.list_eu_merchant_aggregates, locals()), + deserializer=EUMerchantAggregate.from_dict, + raw=raw, + result_key="results", + options=options, + ) + + def list_eu_merchant_hierarchy( + self, + lookup_name: Optional[str] = None, + lookup_name_any_of: Optional[str] = None, + lookup_name_gt: Optional[str] = None, + lookup_name_gte: Optional[str] = None, + lookup_name_lt: Optional[str] = None, + lookup_name_lte: Optional[str] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + listing_status: Optional[str] = None, + listing_status_any_of: Optional[str] = None, + active_from: Optional[Union[str, date]] = None, + active_from_gt: Optional[Union[str, date]] = None, + active_from_gte: Optional[Union[str, date]] = None, + active_from_lt: Optional[Union[str, date]] = None, + active_from_lte: Optional[Union[str, date]] = None, + active_to: Optional[Union[str, date]] = None, + active_to_gt: Optional[Union[str, date]] = None, + active_to_gte: Optional[Union[str, date]] = None, + active_to_lt: Optional[Union[str, date]] = None, + active_to_lte: Optional[Union[str, date]] = None, + limit: Optional[int] = None, + sort: Optional[Union[str, Sort]] = None, + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[EUMerchantHierarchy], HTTPResponse]: + """ + Reference data mapping merchants to parent companies, tickers, sectors, + and industries across Fable's European consumer transaction panel. + + Use lookup_name + active_from/active_to to join with merchant-aggregates + for point-in-time queries. + """ + url = "/consumer-spending/eu/v1/merchant-hierarchy" + + return self._paginate( + path=url, + params=self._get_params(self.list_eu_merchant_hierarchy, locals()), + deserializer=EUMerchantHierarchy.from_dict, + raw=raw, + result_key="results", + options=options, + ) diff --git a/massive/rest/futures.py b/massive/rest/futures.py index 69d82c38..8973c7af 100644 --- a/massive/rest/futures.py +++ b/massive/rest/futures.py @@ -21,7 +21,7 @@ class FuturesClient(BaseClient): """ Client for the Futures REST Endpoints - (aligned with the paths from /futures/vX/...) + (aligned with the paths from /futures/v1/...) """ def list_futures_aggregates( @@ -40,7 +40,7 @@ def list_futures_aggregates( options: Optional[RequestOptionBuilder] = None, ) -> Union[Iterator[FuturesAgg], HTTPResponse]: """ - Endpoint: GET /futures/vX/aggs/{ticker} + Endpoint: GET /futures/v1/aggs/{ticker} Get aggregates for a futures contract in a given time range. This endpoint returns data that includes: @@ -48,7 +48,7 @@ def list_futures_aggregates( - volume, dollar_volume, etc. If `next_url` is present, it will be paginated. """ - url = f"/futures/vX/aggs/{ticker}" + url = f"/futures/v1/aggs/{ticker}" return self._paginate( path=url, params=self._get_params(self.list_futures_aggregates, locals()), @@ -59,24 +59,48 @@ def list_futures_aggregates( def list_futures_contracts( self, + date: Optional[str] = None, + date_gt: Optional[str] = None, + date_gte: Optional[str] = None, + date_lt: Optional[str] = None, + date_lte: Optional[str] = None, product_code: Optional[str] = None, - first_trade_date: Optional[Union[str, date]] = None, - last_trade_date: Optional[Union[str, date]] = None, - as_of: Optional[Union[str, date]] = None, - active: Optional[str] = None, + product_code_any_of: Optional[str] = None, + product_code_gt: Optional[str] = None, + product_code_gte: Optional[str] = None, + product_code_lt: Optional[str] = None, + product_code_lte: Optional[str] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + active: Optional[bool] = None, type: Optional[str] = None, + type_any_of: Optional[str] = None, + first_trade_date: Optional[str] = None, + first_trade_date_gt: Optional[str] = None, + first_trade_date_gte: Optional[str] = None, + first_trade_date_lt: Optional[str] = None, + first_trade_date_lte: Optional[str] = None, + last_trade_date: Optional[str] = None, + last_trade_date_gt: Optional[str] = None, + last_trade_date_gte: Optional[str] = None, + last_trade_date_lt: Optional[str] = None, + last_trade_date_lte: Optional[str] = None, limit: Optional[int] = None, - sort: Optional[Union[str, Sort]] = None, + sort: Optional[str] = None, params: Optional[Dict[str, Any]] = None, raw: bool = False, options: Optional[RequestOptionBuilder] = None, ) -> Union[Iterator[FuturesContract], HTTPResponse]: """ - Endpoint: GET /futures/vX/contracts + Endpoint: GET /futures/v1/contracts The Contracts endpoint returns a paginated list of futures contracts. """ - url = "/futures/vX/contracts" + url = "/futures/v1/contracts" return self._paginate( path=url, params=self._get_params(self.list_futures_contracts, locals()), @@ -85,53 +109,53 @@ def list_futures_contracts( options=options, ) - def get_futures_contract_details( - self, - ticker: str, - as_of: Optional[Union[str, date]] = None, - params: Optional[Dict[str, Any]] = None, - raw: bool = False, - options: Optional[RequestOptionBuilder] = None, - ) -> Union[FuturesContract, HTTPResponse]: - """ - Endpoint: GET /futures/vX/contracts/{ticker} - - Returns details for a single contract at a specified point in time. - (No next_url in the response -> just a single get). - """ - url = f"/futures/vX/contracts/{ticker}" - return self._get( - path=url, - params=self._get_params(self.get_futures_contract_details, locals()), - deserializer=FuturesContract.from_dict, - raw=raw, - result_key="results", - options=options, - ) - def list_futures_products( self, name: Optional[str] = None, - name_search: Optional[str] = None, - as_of: Optional[Union[str, date]] = None, + name_any_of: Optional[str] = None, + name_gt: Optional[str] = None, + name_gte: Optional[str] = None, + name_lt: Optional[str] = None, + name_lte: Optional[str] = None, + product_code: Optional[str] = None, + product_code_any_of: Optional[str] = None, + product_code_gt: Optional[str] = None, + product_code_gte: Optional[str] = None, + product_code_lt: Optional[str] = None, + product_code_lte: Optional[str] = None, + date: Optional[str] = None, + date_gt: Optional[str] = None, + date_gte: Optional[str] = None, + date_lt: Optional[str] = None, + date_lte: Optional[str] = None, trading_venue: Optional[str] = None, + trading_venue_any_of: Optional[str] = None, + trading_venue_gt: Optional[str] = None, + trading_venue_gte: Optional[str] = None, + trading_venue_lt: Optional[str] = None, + trading_venue_lte: Optional[str] = None, sector: Optional[str] = None, + sector_any_of: Optional[str] = None, sub_sector: Optional[str] = None, + sub_sector_any_of: Optional[str] = None, asset_class: Optional[str] = None, + asset_class_any_of: Optional[str] = None, asset_sub_class: Optional[str] = None, + asset_sub_class_any_of: Optional[str] = None, type: Optional[str] = None, + type_any_of: Optional[str] = None, limit: Optional[int] = None, - sort: Optional[Union[str, Sort]] = None, + sort: Optional[str] = None, params: Optional[Dict[str, Any]] = None, raw: bool = False, options: Optional[RequestOptionBuilder] = None, ) -> Union[Iterator[FuturesProduct], HTTPResponse]: """ - Endpoint: GET /futures/vX/products + Endpoint: GET /futures/v1/products Returns a list of futures products (including combos). """ - url = "/futures/vX/products" + url = "/futures/v1/products" return self._paginate( path=url, params=self._get_params(self.list_futures_products, locals()), @@ -140,31 +164,6 @@ def list_futures_products( options=options, ) - def get_futures_product_details( - self, - product_code: str, - type: Optional[str] = None, - as_of: Optional[Union[str, date]] = None, - params: Optional[Dict[str, Any]] = None, - raw: bool = False, - options: Optional[RequestOptionBuilder] = None, - ) -> Union[FuturesProduct, HTTPResponse]: - """ - Endpoint: GET /futures/vX/products/{product_code} - - Returns the details for a single product as it was at a specific day. - (No next_url -> single get). - """ - url = f"/futures/vX/products/{product_code}" - return self._get( - path=url, - params=self._get_params(self.get_futures_product_details, locals()), - deserializer=FuturesProduct.from_dict, - raw=raw, - result_key="results", - options=options, - ) - def list_futures_quotes( self, ticker: str, @@ -185,11 +184,11 @@ def list_futures_quotes( options: Optional[RequestOptionBuilder] = None, ) -> Union[Iterator[FuturesQuote], HTTPResponse]: """ - Endpoint: GET /futures/vX/quotes/{ticker} + Endpoint: GET /futures/v1/quotes/{ticker} Get quotes for a contract in a given time range (paginated). """ - url = f"/futures/vX/quotes/{ticker}" + url = f"/futures/v1/quotes/{ticker}" return self._paginate( path=url, params=self._get_params(self.list_futures_quotes, locals()), @@ -218,11 +217,11 @@ def list_futures_trades( options: Optional[RequestOptionBuilder] = None, ) -> Union[Iterator[FuturesTrade], HTTPResponse]: """ - Endpoint: GET /futures/vX/trades/{ticker} + Endpoint: GET /futures/v1/trades/{ticker} Get trades for a contract in a given time range (paginated). """ - url = f"/futures/vX/trades/{ticker}" + url = f"/futures/v1/trades/{ticker}" return self._paginate( path=url, params=self._get_params(self.list_futures_trades, locals()), @@ -233,21 +232,36 @@ def list_futures_trades( def list_futures_schedules( self, + product_code: Optional[str] = None, + product_code_any_of: Optional[str] = None, + product_code_gt: Optional[str] = None, + product_code_gte: Optional[str] = None, + product_code_lt: Optional[str] = None, + product_code_lte: Optional[str] = None, session_end_date: Optional[str] = None, + session_end_date_gt: Optional[str] = None, + session_end_date_gte: Optional[str] = None, + session_end_date_lt: Optional[str] = None, + session_end_date_lte: Optional[str] = None, trading_venue: Optional[str] = None, + trading_venue_any_of: Optional[str] = None, + trading_venue_gt: Optional[str] = None, + trading_venue_gte: Optional[str] = None, + trading_venue_lt: Optional[str] = None, + trading_venue_lte: Optional[str] = None, limit: Optional[int] = None, - sort: Optional[Union[str, Sort]] = None, + sort: Optional[str] = None, params: Optional[Dict[str, Any]] = None, raw: bool = False, options: Optional[RequestOptionBuilder] = None, ) -> Union[Iterator[FuturesSchedule], HTTPResponse]: """ - Endpoint: GET /futures/vX/schedules + Endpoint: GET /futures/v1/schedules Returns a list of trading schedules for multiple futures products on a specific date. If `next_url` is present, this is paginated. """ - url = "/futures/vX/schedules" + url = "/futures/v1/schedules" return self._paginate( path=url, params=self._get_params(self.list_futures_schedules, locals()), @@ -256,47 +270,20 @@ def list_futures_schedules( options=options, ) - def list_futures_schedules_by_product_code( - self, - product_code: str, - session_end_date: Optional[str] = None, - session_end_date_lt: Optional[str] = None, - session_end_date_lte: Optional[str] = None, - session_end_date_gt: Optional[str] = None, - session_end_date_gte: Optional[str] = None, - limit: Optional[int] = None, - sort: Optional[Union[str, Sort]] = None, - params: Optional[Dict[str, Any]] = None, - raw: bool = False, - options: Optional[RequestOptionBuilder] = None, - ) -> Union[Iterator[FuturesSchedule], HTTPResponse]: - """ - Endpoint: GET /futures/vX/products/{product_code}/schedules - - Returns schedule data for a single product across (potentially) many trading dates. - """ - url = f"/futures/vX/products/{product_code}/schedules" - return self._paginate( - path=url, - params=self._get_params( - self.list_futures_schedules_by_product_code, locals() - ), - raw=raw, - deserializer=FuturesSchedule.from_dict, - options=options, - ) - def list_futures_market_statuses( self, - product_code_any_of: Optional[str] = None, product_code: Optional[str] = None, + product_code_any_of: Optional[str] = None, + product_code_gt: Optional[str] = None, + product_code_gte: Optional[str] = None, + product_code_lt: Optional[str] = None, + product_code_lte: Optional[str] = None, limit: Optional[int] = None, - sort: Optional[Union[str, Sort]] = None, params: Optional[Dict[str, Any]] = None, raw: bool = False, options: Optional[RequestOptionBuilder] = None, ) -> Union[Iterator[FuturesMarketStatus], HTTPResponse]: - url = "/futures/vX/market-status" + url = "/futures/v1/market-status" return self._paginate( path=url, params=self._get_params(self.list_futures_market_statuses, locals()), @@ -320,12 +307,12 @@ def get_futures_snapshot( product_code_lt: Optional[str] = None, product_code_lte: Optional[str] = None, limit: Optional[int] = None, - sort: Optional[Union[str, Sort]] = None, + sort: Optional[str] = None, params: Optional[Dict[str, Any]] = None, raw: bool = False, options: Optional[RequestOptionBuilder] = None, ) -> Union[Iterator[FuturesSnapshot], HTTPResponse]: - url = "/futures/vX/snapshot" + url = "/futures/v1/snapshot" return self._paginate( path=url, params=self._get_params(self.get_futures_snapshot, locals()), @@ -342,11 +329,11 @@ def list_futures_exchanges( options: Optional[RequestOptionBuilder] = None, ) -> Union[Iterator[FuturesExchange], HTTPResponse]: """ - Endpoint: GET /futures/vX/exchanges + Endpoint: GET /futures/v1/exchanges US futures exchanges and trading venues including major derivatives exchanges (CME, CBOT, NYMEX, COMEX) and other futures market infrastructure for commodity, financial, and other derivative contract trading. """ - url = "/futures/vX/exchanges" + url = "/futures/v1/exchanges" return self._paginate( path=url, params=self._get_params(self.list_futures_exchanges, locals()), diff --git a/massive/rest/models/benzinga.py b/massive/rest/models/benzinga.py index 87287f2e..296ea9f6 100644 --- a/massive/rest/models/benzinga.py +++ b/massive/rest/models/benzinga.py @@ -322,3 +322,22 @@ def from_dict(d): ticker=d.get("ticker"), time=d.get("time"), ) + + +@modelclass +class BenzingaBullsBearsSay: + bear_case: Optional[str] = None + benzinga_id: Optional[str] = None + bull_case: Optional[str] = None + last_updated: Optional[str] = None + ticker: Optional[str] = None + + @staticmethod + def from_dict(d): + return BenzingaBullsBearsSay( + bear_case=d.get("bear_case"), + benzinga_id=d.get("benzinga_id"), + bull_case=d.get("bull_case"), + last_updated=d.get("last_updated"), + ticker=d.get("ticker"), + ) diff --git a/massive/rest/models/economy.py b/massive/rest/models/economy.py index 83070e78..97386235 100644 --- a/massive/rest/models/economy.py +++ b/massive/rest/models/economy.py @@ -85,3 +85,145 @@ def from_dict(d): model_30_year=d.get("model_30_year"), model_5_year=d.get("model_5_year"), ) + + +@modelclass +class FedLaborMarket: + avg_hourly_earnings: Optional[float] = None + date: Optional[str] = None + job_openings: Optional[float] = None + labor_force_participation_rate: Optional[float] = None + unemployment_rate: Optional[float] = None + + @staticmethod + def from_dict(d): + return FedLaborMarket( + avg_hourly_earnings=d.get("avg_hourly_earnings"), + date=d.get("date"), + job_openings=d.get("job_openings"), + labor_force_participation_rate=d.get("labor_force_participation_rate"), + unemployment_rate=d.get("unemployment_rate"), + ) + + +@modelclass +class EUMerchantAggregate: + """ + Aggregated consumer transactions from European credit card panels. + Each row represents daily credit card, debit card, or open banking transactions + (7-day lag) at a tagged merchant or payment processor. + """ + + channel: Optional[str] = None + consumer_type: Optional[str] = None + eight_day_rolling_category_accounts: Optional[int] = None + eight_day_rolling_total_accounts: Optional[int] = None + mcc_group: Optional[str] = None + merchant_industry: Optional[str] = None + merchant_ticker: Optional[str] = None + name: Optional[str] = None + parent_name: Optional[str] = None + published_date: Optional[str] = None + spend_in_distinct_account_key_count: Optional[int] = None + spend_in_spend: Optional[float] = None + spend_in_transaction_count: Optional[int] = None + spend_out_distinct_account_key_count: Optional[int] = None + spend_out_spend: Optional[float] = None + spend_out_transaction_count: Optional[int] = None + total_accounts: Optional[int] = None + total_spend: Optional[float] = None + total_transactions: Optional[int] = None + transaction_currency: Optional[str] = None + transaction_date: Optional[str] = None + twenty_eight_day_rolling_category_accounts: Optional[int] = None + twenty_eight_day_rolling_total_accounts: Optional[int] = None + type: Optional[str] = None + user_country: Optional[str] = None + + @staticmethod + def from_dict(d): + return EUMerchantAggregate( + channel=d.get("channel"), + consumer_type=d.get("consumer_type"), + eight_day_rolling_category_accounts=d.get( + "eight_day_rolling_category_accounts" + ), + eight_day_rolling_total_accounts=d.get("eight_day_rolling_total_accounts"), + mcc_group=d.get("mcc_group"), + merchant_industry=d.get("merchant_industry"), + merchant_ticker=d.get("merchant_ticker"), + name=d.get("name"), + parent_name=d.get("parent_name"), + published_date=d.get("published_date"), + spend_in_distinct_account_key_count=d.get( + "spend_in_distinct_account_key_count" + ), + spend_in_spend=d.get("spend_in_spend"), + spend_in_transaction_count=d.get("spend_in_transaction_count"), + spend_out_distinct_account_key_count=d.get( + "spend_out_distinct_account_key_count" + ), + spend_out_spend=d.get("spend_out_spend"), + spend_out_transaction_count=d.get("spend_out_transaction_count"), + total_accounts=d.get("total_accounts"), + total_spend=d.get("total_spend"), + total_transactions=d.get("total_transactions"), + transaction_currency=d.get("transaction_currency"), + transaction_date=d.get("transaction_date"), + twenty_eight_day_rolling_category_accounts=d.get( + "twenty_eight_day_rolling_category_accounts" + ), + twenty_eight_day_rolling_total_accounts=d.get( + "twenty_eight_day_rolling_total_accounts" + ), + type=d.get("type"), + user_country=d.get("user_country"), + ) + + +@modelclass +class EUMerchantHierarchy: + """ + Reference data mapping merchants to parent companies, tickers, sectors, + and industries across Fable's European consumer transaction panel. + """ + + active_from: Optional[str] = None + active_to: Optional[str] = None + category: Optional[str] = None + grandparent_name: Optional[str] = None + grandparent_ticker: Optional[str] = None + great_grandparent_name: Optional[str] = None + great_grandparent_ticker: Optional[str] = None + industry: Optional[str] = None + industry_group: Optional[str] = None + listing_status: Optional[str] = None + lookup_name: Optional[str] = None + normalized_name: Optional[str] = None + parent_name: Optional[str] = None + parent_ticker: Optional[str] = None + sector: Optional[str] = None + sub_industry: Optional[str] = None + ticker: Optional[str] = None + + @staticmethod + def from_dict(d): + return EUMerchantHierarchy( + active_from=d.get("active_from"), + active_to=d.get("active_to"), + category=d.get("category"), + grandparent_name=d.get("grandparent_name"), + grandparent_ticker=d.get("grandparent_ticker"), + great_grandparent_name=d.get("great_grandparent_name"), + great_grandparent_ticker=d.get("great_grandparent_ticker"), + industry=d.get("industry"), + industry_group=d.get("industry_group"), + listing_status=d.get("listing_status"), + lookup_name=d.get("lookup_name"), + normalized_name=d.get("normalized_name"), + parent_name=d.get("parent_name"), + parent_ticker=d.get("parent_ticker"), + sector=d.get("sector"), + sub_industry=d.get("sub_industry"), + ticker=d.get("ticker"), + ) diff --git a/massive/rest/models/financials.py b/massive/rest/models/financials.py index 2e97eeba..3266da1d 100644 --- a/massive/rest/models/financials.py +++ b/massive/rest/models/financials.py @@ -920,3 +920,389 @@ def from_dict(d): taxonomy=d.get("taxonomy"), tertiary_category=d.get("tertiary_category"), ) + + +@modelclass +class Disclosure: + """ + A single tagged disclosure within an SEC 8-K filing. A filing can produce + multiple disclosures, each classified into primary, secondary, and tertiary + categories with a supporting text excerpt. + """ + + accession_number: Optional[str] = None + cik: Optional[str] = None + filing_date: Optional[str] = None + filing_url: Optional[str] = None + primary_category: Optional[str] = None + secondary_category: Optional[str] = None + supporting_text: Optional[str] = None + tertiary_category: Optional[str] = None + tickers: Optional[List[str]] = None + + @staticmethod + def from_dict(d): + return Disclosure( + accession_number=d.get("accession_number"), + cik=d.get("cik"), + filing_date=d.get("filing_date"), + filing_url=d.get("filing_url"), + primary_category=d.get("primary_category"), + secondary_category=d.get("secondary_category"), + supporting_text=d.get("supporting_text"), + tertiary_category=d.get("tertiary_category"), + tickers=d.get("tickers"), + ) + + +@modelclass +class DisclosureTaxonomy: + """ + A single 8-K disclosure classification, part of the complete list of + classifications used in the 8-K disclosures endpoint. + """ + + description: Optional[str] = None + primary_category: Optional[str] = None + secondary_category: Optional[str] = None + taxonomy: Optional[str] = None + tertiary_category: Optional[str] = None + + @staticmethod + def from_dict(d): + return DisclosureTaxonomy( + description=d.get("description"), + primary_category=d.get("primary_category"), + secondary_category=d.get("secondary_category"), + taxonomy=d.get("taxonomy"), + tertiary_category=d.get("tertiary_category"), + ) + + +@modelclass +@dataclass +class Filing13F: + """SEC Form 13F filings data showing institutional investment manager holdings.""" + + accession_number: Optional[str] = None + cusip: Optional[str] = None + file_number: Optional[str] = None + filer_cik: Optional[str] = None + filing_date: Optional[str] = None + filing_url: Optional[str] = None + film_number: Optional[str] = None + form_type: Optional[str] = None + investment_discretion: Optional[str] = None + issuer_name: Optional[str] = None + market_value: Optional[int] = None + other_managers: Optional[List[str]] = None + period: Optional[str] = None + put_call: Optional[str] = None + shares_or_principal_amount: Optional[int] = None + shares_or_principal_type: Optional[str] = None + title_of_class: Optional[str] = None + voting_authority_none: Optional[int] = None + voting_authority_shared: Optional[int] = None + voting_authority_sole: Optional[int] = None + + @staticmethod + def from_dict(d: Optional[Dict[str, Any]]) -> "Filing13F": + if not d: + return Filing13F() + return Filing13F( + accession_number=d.get("accession_number"), + cusip=d.get("cusip"), + file_number=d.get("file_number"), + filer_cik=d.get("filer_cik"), + filing_date=d.get("filing_date"), + filing_url=d.get("filing_url"), + film_number=d.get("film_number"), + form_type=d.get("form_type"), + investment_discretion=d.get("investment_discretion"), + issuer_name=d.get("issuer_name"), + market_value=d.get("market_value"), + other_managers=d.get("other_managers"), + period=d.get("period"), + put_call=d.get("put_call"), + shares_or_principal_amount=d.get("shares_or_principal_amount"), + shares_or_principal_type=d.get("shares_or_principal_type"), + title_of_class=d.get("title_of_class"), + voting_authority_none=d.get("voting_authority_none"), + voting_authority_shared=d.get("voting_authority_shared"), + voting_authority_sole=d.get("voting_authority_sole"), + ) + + +@modelclass +class FilingSection: + """SEC document text section from a 10-K/10-Q (raw text content).""" + + cik: Optional[str] = None + filing_date: Optional[str] = None + filing_url: Optional[str] = None + period_end: Optional[str] = None + section: Optional[str] = None + text: Optional[str] = None + ticker: Optional[str] = None + + @staticmethod + def from_dict(d): + return FilingSection( + cik=d.get("cik"), + filing_date=d.get("filing_date"), + filing_url=d.get("filing_url"), + period_end=d.get("period_end"), + section=d.get("section"), + text=d.get("text"), + ticker=d.get("ticker"), + ) + + +@modelclass +@dataclass +class FilingFootnote: + """Footnote from SEC Form 3/4 filings.""" + + id: Optional[str] = None + description: Optional[str] = None + + @staticmethod + def from_dict(d: Optional[Dict[str, Any]]) -> "FilingFootnote": + if not d: + return FilingFootnote() + return FilingFootnote( + id=d.get("id"), + description=d.get("description"), + ) + + +@modelclass +@dataclass +class FilingForm3: + """SEC Form 3 filings reporting initial statements of beneficial ownership of securities. + Filed by corporate insiders (directors, officers, and 10%+ shareholders) when they first acquire a position. + """ + + accession_number: Optional[str] = None + aff_10b5_one: Optional[bool] = None + date_of_original_submission: Optional[str] = None + direct_or_indirect: Optional[str] = None + exercise_date: Optional[str] = None + exercise_price: Optional[float] = None + filing_date: Optional[str] = None + filing_url: Optional[str] = None + footnotes: Optional[List[FilingFootnote]] = None + form_type: Optional[str] = None + is_director: Optional[bool] = None + is_officer: Optional[bool] = None + is_other: Optional[bool] = None + is_ten_percent_owner: Optional[bool] = None + issuer_cik: Optional[str] = None + issuer_name: Optional[str] = None + nature_of_ownership: Optional[str] = None + not_subject_to_section_16: Optional[bool] = None + officer_title: Optional[str] = None + owner_cik: Optional[str] = None + owner_name: Optional[str] = None + period_of_report: Optional[str] = None + remarks: Optional[str] = None + security_title: Optional[str] = None + security_type: Optional[str] = None + shares_owned: Optional[float] = None + tickers: Optional[List[str]] = None + underlying_security_shares: Optional[float] = None + underlying_security_title: Optional[str] = None + + @staticmethod + def from_dict(d: Optional[Dict[str, Any]]) -> "FilingForm3": + if not d: + return FilingForm3() + footnotes = d.get("footnotes") + return FilingForm3( + accession_number=d.get("accession_number"), + aff_10b5_one=d.get("aff_10b5_one"), + date_of_original_submission=d.get("date_of_original_submission"), + direct_or_indirect=d.get("direct_or_indirect"), + exercise_date=d.get("exercise_date"), + exercise_price=d.get("exercise_price"), + filing_date=d.get("filing_date"), + filing_url=d.get("filing_url"), + footnotes=( + [FilingFootnote.from_dict(f) for f in footnotes] + if footnotes is not None + else None + ), + form_type=d.get("form_type"), + is_director=d.get("is_director"), + is_officer=d.get("is_officer"), + is_other=d.get("is_other"), + is_ten_percent_owner=d.get("is_ten_percent_owner"), + issuer_cik=d.get("issuer_cik"), + issuer_name=d.get("issuer_name"), + nature_of_ownership=d.get("nature_of_ownership"), + not_subject_to_section_16=d.get("not_subject_to_section_16"), + officer_title=d.get("officer_title"), + owner_cik=d.get("owner_cik"), + owner_name=d.get("owner_name"), + period_of_report=d.get("period_of_report"), + remarks=d.get("remarks"), + security_title=d.get("security_title"), + security_type=d.get("security_type"), + shares_owned=d.get("shares_owned"), + tickers=d.get("tickers"), + underlying_security_shares=d.get("underlying_security_shares"), + underlying_security_title=d.get("underlying_security_title"), + ) + + +@modelclass +@dataclass +class FilingForm4: + """SEC Form 4 filings reporting changes in beneficial ownership of securities. + Filed by corporate insiders (directors, officers, and 10%+ shareholders) within two business days of a transaction. + """ + + accession_number: Optional[str] = None + aff_10b5_one: Optional[bool] = None + date_of_original_submission: Optional[str] = None + deemed_execution_date: Optional[str] = None + direct_or_indirect: Optional[str] = None + equity_swap_involved: Optional[bool] = None + exercise_date: Optional[str] = None + exercise_price: Optional[float] = None + expiration_date: Optional[str] = None + filing_date: Optional[str] = None + filing_url: Optional[str] = None + footnotes: Optional[List[FilingFootnote]] = None + form_type: Optional[str] = None + is_director: Optional[bool] = None + is_officer: Optional[bool] = None + is_other: Optional[bool] = None + is_ten_percent_owner: Optional[bool] = None + issuer_cik: Optional[str] = None + issuer_name: Optional[str] = None + nature_of_ownership: Optional[str] = None + not_subject_to_section_16: Optional[bool] = None + officer_title: Optional[str] = None + owner_cik: Optional[str] = None + owner_name: Optional[str] = None + period_of_report: Optional[str] = None + record_type: Optional[str] = None + remarks: Optional[str] = None + security_title: Optional[str] = None + security_type: Optional[str] = None + shares_owned_following_transaction: Optional[float] = None + tickers: Optional[List[str]] = None + transaction_acquired_disposed: Optional[str] = None + transaction_code: Optional[str] = None + transaction_date: Optional[str] = None + transaction_price_per_share: Optional[float] = None + transaction_shares: Optional[float] = None + transaction_timeliness: Optional[str] = None + transaction_value: Optional[float] = None + underlying_security_shares: Optional[float] = None + underlying_security_title: Optional[str] = None + + @staticmethod + def from_dict(d: Optional[Dict[str, Any]]) -> "FilingForm4": + if not d: + return FilingForm4() + footnotes = d.get("footnotes") + return FilingForm4( + accession_number=d.get("accession_number"), + aff_10b5_one=d.get("aff_10b5_one"), + date_of_original_submission=d.get("date_of_original_submission"), + deemed_execution_date=d.get("deemed_execution_date"), + direct_or_indirect=d.get("direct_or_indirect"), + equity_swap_involved=d.get("equity_swap_involved"), + exercise_date=d.get("exercise_date"), + exercise_price=d.get("exercise_price"), + expiration_date=d.get("expiration_date"), + filing_date=d.get("filing_date"), + filing_url=d.get("filing_url"), + footnotes=( + [FilingFootnote.from_dict(f) for f in footnotes] + if footnotes is not None + else None + ), + form_type=d.get("form_type"), + is_director=d.get("is_director"), + is_officer=d.get("is_officer"), + is_other=d.get("is_other"), + is_ten_percent_owner=d.get("is_ten_percent_owner"), + issuer_cik=d.get("issuer_cik"), + issuer_name=d.get("issuer_name"), + nature_of_ownership=d.get("nature_of_ownership"), + not_subject_to_section_16=d.get("not_subject_to_section_16"), + officer_title=d.get("officer_title"), + owner_cik=d.get("owner_cik"), + owner_name=d.get("owner_name"), + period_of_report=d.get("period_of_report"), + record_type=d.get("record_type"), + remarks=d.get("remarks"), + security_title=d.get("security_title"), + security_type=d.get("security_type"), + shares_owned_following_transaction=d.get( + "shares_owned_following_transaction" + ), + tickers=d.get("tickers"), + transaction_acquired_disposed=d.get("transaction_acquired_disposed"), + transaction_code=d.get("transaction_code"), + transaction_date=d.get("transaction_date"), + transaction_price_per_share=d.get("transaction_price_per_share"), + transaction_shares=d.get("transaction_shares"), + transaction_timeliness=d.get("transaction_timeliness"), + transaction_value=d.get("transaction_value"), + underlying_security_shares=d.get("underlying_security_shares"), + underlying_security_title=d.get("underlying_security_title"), + ) + + +@modelclass +class Filing8K: + """Parsed 8-K filing with item-level text content.""" + + accession_number: Optional[str] = None + cik: Optional[str] = None + filing_date: Optional[str] = None + filing_url: Optional[str] = None + form_type: Optional[str] = None + items_text: Optional[str] = None + ticker: Optional[str] = None + + @staticmethod + def from_dict(d): + return Filing8K( + accession_number=d.get("accession_number"), + cik=d.get("cik"), + filing_date=d.get("filing_date"), + filing_url=d.get("filing_url"), + form_type=d.get("form_type"), + items_text=d.get("items_text"), + ticker=d.get("ticker"), + ) + + +@modelclass +class FilingIndex: + """Master index entry for any SEC filing (10-K, 8-K, 10-Q, etc.).""" + + accession_number: Optional[str] = None + cik: Optional[str] = None + filing_date: Optional[str] = None + filing_url: Optional[str] = None + form_type: Optional[str] = None + issuer_name: Optional[str] = None + ticker: Optional[str] = None + + @staticmethod + def from_dict(d): + return FilingIndex( + accession_number=d.get("accession_number"), + cik=d.get("cik"), + filing_date=d.get("filing_date"), + filing_url=d.get("filing_url"), + form_type=d.get("form_type"), + issuer_name=d.get("issuer_name"), + ticker=d.get("ticker"), + ) diff --git a/massive/rest/models/futures.py b/massive/rest/models/futures.py index b9bd3c0b..c2be928c 100644 --- a/massive/rest/models/futures.py +++ b/massive/rest/models/futures.py @@ -1,4 +1,4 @@ -from typing import Optional, List +from typing import Optional, List, Union from ...modelclass import modelclass @@ -6,7 +6,7 @@ class FuturesAgg: """ A single aggregate bar for a futures contract in a given time window. - Corresponds to /futures/vX/aggs/{ticker}. + Corresponds to /futures/v1/aggs/{ticker}. """ ticker: Optional[str] = None @@ -42,7 +42,7 @@ def from_dict(d): class FuturesContract: """ Represents a single futures contract (or a 'combo' contract). - Corresponds to /futures/vX/contracts endpoints. + Corresponds to /futures/v1/contracts endpoints. """ ticker: Optional[str] = None @@ -50,7 +50,7 @@ class FuturesContract: trading_venue: Optional[str] = None name: Optional[str] = None type: Optional[str] = None - as_of: Optional[str] = None + date: Optional[str] = None active: Optional[bool] = None first_trade_date: Optional[str] = None last_trade_date: Optional[str] = None @@ -61,7 +61,7 @@ class FuturesContract: settlement_tick_size: Optional[float] = None spread_tick_size: Optional[float] = None trade_tick_size: Optional[float] = None - maturity: Optional[str] = None + group_code: Optional[str] = None @staticmethod def from_dict(d): @@ -71,7 +71,7 @@ def from_dict(d): trading_venue=d.get("trading_venue"), name=d.get("name"), type=d.get("type"), - as_of=d.get("as_of"), + date=d.get("date"), active=d.get("active"), first_trade_date=d.get("first_trade_date"), last_trade_date=d.get("last_trade_date"), @@ -82,7 +82,7 @@ def from_dict(d): settlement_tick_size=d.get("settlement_tick_size"), spread_tick_size=d.get("spread_tick_size"), trade_tick_size=d.get("trade_tick_size"), - maturity=d.get("maturity"), + group_code=d.get("group_code"), ) @@ -90,16 +90,15 @@ def from_dict(d): class FuturesProduct: """ Represents a single futures product (or product 'combo'). - Corresponds to /futures/vX/products endpoints. + Corresponds to /futures/v1/products endpoints. """ product_code: Optional[str] = None name: Optional[str] = None - as_of: Optional[str] = None + date: Optional[str] = None trading_venue: Optional[str] = None asset_class: Optional[str] = None asset_sub_class: Optional[str] = None - clearing_channel: Optional[str] = None sector: Optional[str] = None sub_sector: Optional[str] = None type: Optional[str] = None @@ -110,17 +109,16 @@ class FuturesProduct: settlement_type: Optional[str] = None trade_currency_code: Optional[str] = None unit_of_measure: Optional[str] = None - unit_of_measure_quantity: Optional[float] = None + unit_of_measure_qty: Optional[float] = None @staticmethod def from_dict(d): return FuturesProduct( product_code=d.get("product_code"), name=d.get("name"), - as_of=d.get("as_of"), + date=d.get("date"), trading_venue=d.get("trading_venue"), asset_class=d.get("asset_class"), - clearing_channel=d.get("clearing_channel"), asset_sub_class=d.get("asset_sub_class"), sector=d.get("sector"), sub_sector=d.get("sub_sector"), @@ -132,7 +130,7 @@ def from_dict(d): settlement_type=d.get("settlement_type"), trade_currency_code=d.get("trade_currency_code"), unit_of_measure=d.get("unit_of_measure"), - unit_of_measure_quantity=d.get("unit_of_measure_quantity"), + unit_of_measure_qty=d.get("unit_of_measure_qty"), ) @@ -140,7 +138,7 @@ def from_dict(d): class FuturesQuote: """ Represents a futures NBBO quote within a given time range. - Corresponds to /futures/vX/quotes/{ticker} + Corresponds to /futures/v1/quotes/{ticker} """ ticker: Optional[str] = None @@ -152,6 +150,9 @@ class FuturesQuote: bid_price: Optional[float] = None bid_size: Optional[float] = None bid_timestamp: Optional[int] = None + channel: Optional[int] = None + report_sequence: Optional[int] = None + sequence_number: Optional[int] = None @staticmethod def from_dict(d): @@ -165,6 +166,9 @@ def from_dict(d): bid_price=d.get("bid_price"), bid_size=d.get("bid_size"), bid_timestamp=d.get("bid_timestamp"), + channel=d.get("channel"), + report_sequence=d.get("report_sequence"), + sequence_number=d.get("sequence_number"), ) @@ -172,14 +176,17 @@ def from_dict(d): class FuturesTrade: """ Represents a futures trade within a given time range. - Corresponds to /futures/vX/trades/{ticker} + Corresponds to /futures/v1/trades/{ticker} """ ticker: Optional[str] = None timestamp: Optional[int] = None session_end_date: Optional[str] = None + channel: Optional[int] = None price: Optional[float] = None size: Optional[float] = None + report_sequence: Optional[int] = None + sequence_number: Optional[int] = None @staticmethod def from_dict(d): @@ -187,75 +194,76 @@ def from_dict(d): ticker=d.get("ticker"), timestamp=d.get("timestamp"), session_end_date=d.get("session_end_date"), + channel=d.get("channel"), price=d.get("price"), size=d.get("size"), + report_sequence=d.get("report_sequence"), + sequence_number=d.get("sequence_number"), ) @modelclass -class FuturesScheduleEvent: +class FuturesSchedule: """ - Represents a single market event for a schedule (preopen, open, closed, etc.). + Represents a single schedule event for a given session_end_date and product. + Corresponds to /futures/v1/schedules """ event: Optional[str] = None timestamp: Optional[str] = None - - @staticmethod - def from_dict(d): - return FuturesScheduleEvent( - event=d.get("event"), - timestamp=d.get("timestamp"), - ) - - -@modelclass -class FuturesSchedule: - """ - Represents a single schedule for a given session_end_date, with events. - Corresponds to /futures/vX/schedules, /futures/vX/schedules/{product_code} - """ - session_end_date: Optional[str] = None product_code: Optional[str] = None trading_venue: Optional[str] = None product_name: Optional[str] = None - schedule: Optional[List[FuturesScheduleEvent]] = None @staticmethod def from_dict(d): return FuturesSchedule( + event=d.get("event"), + timestamp=d.get("timestamp"), session_end_date=d.get("session_end_date"), product_code=d.get("product_code"), trading_venue=d.get("trading_venue"), product_name=d.get("product_name"), - schedule=[ - FuturesScheduleEvent.from_dict(ev) for ev in d.get("schedule", []) - ], ) @modelclass class FuturesMarketStatus: - trading_venue: Optional[str] = None - market_status: Optional[str] = ( - None # Enum: pre_open, open, close, pause, post_close_pre_open - ) + market_event: Optional[str] = None + name: Optional[str] = None product_code: Optional[str] = None + session_end_date: Optional[str] = None + timestamp: Optional[str] = None + trading_venue: Optional[str] = None @staticmethod def from_dict(d): return FuturesMarketStatus( - trading_venue=d.get("trading_venue"), - market_status=d.get("market_status"), + market_event=d.get("market_event"), + name=d.get("name"), product_code=d.get("product_code"), + session_end_date=d.get("session_end_date"), + timestamp=d.get("timestamp"), + trading_venue=d.get("trading_venue"), ) @modelclass class FuturesSnapshotDetails: open_interest: Optional[int] = None - settlement_date: Optional[int] = None + settlement_date: Optional[Union[str, int]] = None + ticker: Optional[str] = None + product_code: Optional[str] = None + + @staticmethod + def from_dict(d): + return FuturesSnapshotDetails( + open_interest=d.get("open_interest"), + settlement_date=d.get("settlement_date"), + ticker=d.get("ticker"), + product_code=d.get("product_code"), + ) @modelclass @@ -354,6 +362,7 @@ def from_dict(d): class FuturesSnapshot: ticker: Optional[str] = None product_code: Optional[str] = None + details: Optional[FuturesSnapshotDetails] = None last_minute: Optional[FuturesSnapshotMinute] = None last_quote: Optional[FuturesSnapshotQuote] = None @@ -362,14 +371,11 @@ class FuturesSnapshot: @staticmethod def from_dict(d): + details_dict = d.get("details") or {} return FuturesSnapshot( - ticker=d.get("ticker"), - product_code=d.get("product_code"), - details=( - FuturesSnapshotDetails.from_dict(d.get("details", {})) - if d.get("details") - else None - ), + ticker=d.get("ticker") or details_dict.get("ticker"), + product_code=d.get("product_code") or details_dict.get("product_code"), + details=FuturesSnapshotDetails.from_dict(details_dict), last_minute=( FuturesSnapshotMinute.from_dict(d.get("last_minute", {})) if d.get("last_minute") @@ -397,7 +403,7 @@ def from_dict(d): class FuturesExchange: """ Represents a futures exchange or trading venue. - Corresponds to /futures/vX/exchanges endpoint. + Corresponds to /futures/v1/exchanges endpoint. """ acronym: Optional[str] = None diff --git a/massive/rest/models/snapshot.py b/massive/rest/models/snapshot.py index 3d38abe2..0f6dd160 100644 --- a/massive/rest/models/snapshot.py +++ b/massive/rest/models/snapshot.py @@ -7,7 +7,8 @@ @modelclass class MinuteSnapshot: - "Most recent minute bar." + """Most recent minute bar.""" + accumulated_volume: Optional[float] = None open: Optional[float] = None high: Optional[float] = None @@ -18,20 +19,24 @@ class MinuteSnapshot: otc: Optional[bool] = None timestamp: Optional[int] = None transactions: Optional[int] = None + fractional_volume: Optional[str] = None + fractional_accumulated_volume: Optional[str] = None @staticmethod def from_dict(d): return MinuteSnapshot( - d.get("av", None), - d.get("o", None), - d.get("h", None), - d.get("l", None), - d.get("c", None), - d.get("v", None), - d.get("vw", None), - d.get("otc", None), - d.get("t", None), - d.get("n", None), + accumulated_volume=d.get("av"), + open=d.get("o"), + high=d.get("h"), + low=d.get("l"), + close=d.get("c"), + volume=d.get("v"), + vwap=d.get("vw"), + otc=d.get("otc"), + timestamp=d.get("t"), + transactions=d.get("n"), + fractional_volume=d.get("dv"), + fractional_accumulated_volume=d.get("dav"), ) @@ -318,10 +323,32 @@ class UniversalSnapshotSession: low: Optional[float] = None previous_close: Optional[float] = None volume: Optional[float] = None + vwap: Optional[float] = None + last_updated: Optional[int] = None + fractional_volume: Optional[str] = None @staticmethod def from_dict(d): - return UniversalSnapshotSession(**d) + return UniversalSnapshotSession( + price=d.get("price"), + change=d.get("change"), + change_percent=d.get("change_percent"), + early_trading_change=d.get("early_trading_change"), + early_trading_change_percent=d.get("early_trading_change_percent"), + regular_trading_change=d.get("regular_trading_change"), + regular_trading_change_percent=d.get("regular_trading_change_percent"), + late_trading_change=d.get("late_trading_change"), + late_trading_change_percent=d.get("late_trading_change_percent"), + open=d.get("open"), + close=d.get("close"), + high=d.get("high"), + low=d.get("low"), + previous_close=d.get("previous_close"), + volume=d.get("volume"), + vwap=d.get("vwap"), + last_updated=d.get("last_updated"), + fractional_volume=d.get("decimal_volume"), + ) @modelclass @@ -330,8 +357,10 @@ class UniversalSnapshotLastQuote: ask: Optional[float] = None ask_size: Optional[float] = None + ask_exchange: Optional[int] = None bid: Optional[float] = None bid_size: Optional[float] = None + bid_exchange: Optional[int] = None midpoint: Optional[float] = None exchange: Optional[int] = None timeframe: Optional[str] = None @@ -339,7 +368,18 @@ class UniversalSnapshotLastQuote: @staticmethod def from_dict(d): - return UniversalSnapshotLastQuote(**d) + return UniversalSnapshotLastQuote( + ask=d.get("ask"), + ask_size=d.get("ask_size"), + ask_exchange=d.get("ask_exchange"), + bid=d.get("bid"), + bid_size=d.get("bid_size"), + bid_exchange=d.get("bid_exchange"), + midpoint=d.get("midpoint"), + exchange=d.get("exchange"), + timeframe=d.get("timeframe"), + last_updated=d.get("last_updated"), + ) @modelclass @@ -355,10 +395,51 @@ class UniversalSnapshotLastTrade: last_updated: Optional[int] = None participant_timestamp: Optional[int] = None sip_timestamp: Optional[int] = None + fractional_size: Optional[str] = None + + @staticmethod + def from_dict(d): + return UniversalSnapshotLastTrade( + id=d.get("id"), + price=d.get("price"), + size=d.get("size"), + exchange=d.get("exchange"), + conditions=d.get("conditions"), + timeframe=d.get("timeframe"), + last_updated=d.get("last_updated"), + participant_timestamp=d.get("participant_timestamp"), + sip_timestamp=d.get("sip_timestamp"), + fractional_size=d.get("decimal_size"), + ) + + +@modelclass +class UniversalSnapshotLastMinute: + """Contains the most recent minute-level aggregate for the asset.""" + + open: Optional[float] = None + close: Optional[float] = None + high: Optional[float] = None + low: Optional[float] = None + volume: Optional[float] = None + vwap: Optional[float] = None + transactions: Optional[int] = None + last_updated: Optional[int] = None + fractional_volume: Optional[str] = None @staticmethod def from_dict(d): - return UniversalSnapshotLastTrade(**d) + return UniversalSnapshotLastMinute( + open=d.get("open"), + close=d.get("close"), + high=d.get("high"), + low=d.get("low"), + volume=d.get("volume"), + vwap=d.get("vwap"), + transactions=d.get("transactions"), + last_updated=d.get("last_updated"), + fractional_volume=d.get("decimal_volume"), + ) @modelclass @@ -374,7 +455,14 @@ class UniversalSnapshotUnderlyingAsset: @staticmethod def from_dict(d): - return UniversalSnapshotUnderlyingAsset(**d) + return UniversalSnapshotUnderlyingAsset( + ticker=d.get("ticker"), + price=d.get("price"), + value=d.get("value"), + change_to_break_even=d.get("change_to_break_even"), + timeframe=d.get("timeframe"), + last_updated=d.get("last_updated"), + ) @modelclass @@ -389,18 +477,25 @@ class UniversalSnapshotDetails: @staticmethod def from_dict(d): - return UniversalSnapshotDetails(**d) + return UniversalSnapshotDetails( + contract_type=d.get("contract_type"), + exercise_style=d.get("exercise_style"), + expiration_date=d.get("expiration_date"), + shares_per_contract=d.get("shares_per_contract"), + strike_price=d.get("strike_price"), + ) @modelclass class UniversalSnapshot: - """Contains snapshot data for an asset.""" + """Contains snapshot data for an asset (stocks, options, indices, fx, crypto).""" ticker: Optional[str] = None type: Optional[str] = None session: Optional[UniversalSnapshotSession] = None last_quote: Optional[UniversalSnapshotLastQuote] = None last_trade: Optional[UniversalSnapshotLastTrade] = None + last_minute: Optional[UniversalSnapshotLastMinute] = None greeks: Optional[Greeks] = None underlying_asset: Optional[UniversalSnapshotUnderlyingAsset] = None details: Optional[UniversalSnapshotDetails] = None @@ -412,12 +507,15 @@ class UniversalSnapshot: fair_market_value: Optional[float] = None error: Optional[str] = None message: Optional[str] = None + value: Optional[float] = None + last_updated: Optional[int] = None + timeframe: Optional[str] = None @staticmethod def from_dict(d): return UniversalSnapshot( - ticker=d.get("ticker", None), - type=d.get("type", None), + ticker=d.get("ticker"), + type=d.get("type"), session=( None if "session" not in d @@ -433,7 +531,12 @@ def from_dict(d): if "last_trade" not in d else UniversalSnapshotLastTrade.from_dict(d["last_trade"]) ), - greeks=None if "greeks" not in d else Greeks.from_dict(d["greeks"]), + last_minute=( + None + if "last_minute" not in d + else UniversalSnapshotLastMinute.from_dict(d["last_minute"]) + ), + greeks=(None if "greeks" not in d else Greeks.from_dict(d["greeks"])), underlying_asset=( None if "underlying_asset" not in d @@ -444,12 +547,15 @@ def from_dict(d): if "details" not in d else UniversalSnapshotDetails.from_dict(d["details"]) ), - break_even_price=d.get("break_even_price", None), - implied_volatility=d.get("implied_volatility", None), - open_interest=d.get("open_interest", None), - market_status=d.get("market_status", None), - name=d.get("name", None), - fair_market_value=d.get("fmv", None), - error=d.get("error", None), - message=d.get("message", None), + break_even_price=d.get("break_even_price"), + implied_volatility=d.get("implied_volatility"), + open_interest=d.get("open_interest"), + market_status=d.get("market_status"), + name=d.get("name"), + fair_market_value=d.get("fmv"), + error=d.get("error"), + message=d.get("message"), + value=d.get("value"), + last_updated=d.get("last_updated"), + timeframe=d.get("timeframe"), ) diff --git a/massive/rest/models/trades.py b/massive/rest/models/trades.py index 25b9adc7..e298ed29 100644 --- a/massive/rest/models/trades.py +++ b/massive/rest/models/trades.py @@ -17,6 +17,7 @@ class Trade: tape: Optional[int] = None trf_id: Optional[int] = None trf_timestamp: Optional[int] = None + decimal_size: Optional[str] = None @staticmethod def from_dict(d): @@ -25,7 +26,8 @@ def from_dict(d): @modelclass class LastTrade: - "Contains data for the most recent trade for a given ticker symbol." + """Contains data for the most recent trade for a given ticker symbol.""" + ticker: Optional[str] = None trf_timestamp: Optional[int] = None sequence_number: Optional[float] = None @@ -39,23 +41,25 @@ class LastTrade: size: Optional[float] = None exchange: Optional[int] = None tape: Optional[int] = None + fractional_size: Optional[str] = None @staticmethod def from_dict(d): return LastTrade( - d.get("T", None), - d.get("f", None), - d.get("q", None), - d.get("t", None), - d.get("y", None), - d.get("c", None), - d.get("e", None), - d.get("i", None), - d.get("p", None), - d.get("r", None), - d.get("s", None), - d.get("x", None), - d.get("z", None), + ticker=d.get("T"), + trf_timestamp=d.get("f"), + sequence_number=d.get("q"), + sip_timestamp=d.get("t"), + participant_timestamp=d.get("y"), + conditions=d.get("c"), + correction=d.get("e"), + id=d.get("i"), + price=d.get("p"), + trf_id=d.get("r"), + size=d.get("s"), + exchange=d.get("x"), + tape=d.get("z"), + fractional_size=d.get("ds"), ) diff --git a/massive/rest/reference.py b/massive/rest/reference.py index 446d9f13..b6886c55 100644 --- a/massive/rest/reference.py +++ b/massive/rest/reference.py @@ -28,6 +28,14 @@ ShortVolume, RiskFactor, RiskFactorTaxonomy, + Disclosure, + DisclosureTaxonomy, + FilingSection, + Filing8K, + Filing13F, + FilingForm3, + FilingForm4, + FilingIndex, ) from urllib3 import HTTPResponse from datetime import date @@ -793,21 +801,22 @@ def list_stocks_filings_risk_factors( cik_gte: Optional[str] = None, cik_lt: Optional[str] = None, cik_lte: Optional[str] = None, - limit: Optional[int] = None, - sort: Optional[Union[str, Sort]] = None, + limit: Optional[int] = 100, + sort: Optional[Union[str, Sort]] = "filing_date.desc", params: Optional[Dict[str, Any]] = None, raw: bool = False, options: Optional[RequestOptionBuilder] = None, ) -> Union[Iterator[RiskFactor], HTTPResponse]: """ - Endpoint: GET /stocks/filings/vX/risk-factors + Get categorized risk factors extracted from 10-K filings (with supporting_text). """ url = "/stocks/filings/vX/risk-factors" return self._paginate( path=url, params=self._get_params(self.list_stocks_filings_risk_factors, locals()), - raw=raw, + result_key="results", deserializer=RiskFactor.from_dict, + raw=raw, options=options, ) @@ -836,20 +845,364 @@ def list_stocks_taxonomies_risk_factors( tertiary_category_gte: Optional[str] = None, tertiary_category_lt: Optional[str] = None, tertiary_category_lte: Optional[str] = None, - limit: Optional[int] = None, - sort: Optional[Union[str, Sort]] = None, + limit: Optional[int] = 200, + sort: Optional[Union[str, Sort]] = "taxonomy.desc", params: Optional[Dict[str, Any]] = None, raw: bool = False, options: Optional[RequestOptionBuilder] = None, ) -> Union[Iterator[RiskFactorTaxonomy], HTTPResponse]: """ - Endpoint: GET /stocks/taxonomies/vX/risk-factors + Get the taxonomy/categories used to classify risk factors (kept old name for backward compatibility). """ url = "/stocks/taxonomies/vX/risk-factors" return self._paginate( path=url, params=self._get_params(self.list_stocks_taxonomies_risk_factors, locals()), - raw=raw, + result_key="results", deserializer=RiskFactorTaxonomy.from_dict, + raw=raw, + options=options, + ) + + def list_stocks_filings_8k_disclosures( + self, + cik: Optional[str] = None, + cik_any_of: Optional[str] = None, + tickers: Optional[str] = None, + tickers_all_of: Optional[str] = None, + tickers_any_of: Optional[str] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_any_of: Optional[str] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + tertiary_category: Optional[str] = None, + limit: Optional[int] = 100, + sort: Optional[Union[str, Sort]] = "filing_date.desc", + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[Disclosure], HTTPResponse]: + """ + SEC 8-K filing disclosure categorization. A single 8-K filing can produce + multiple rows when it covers multiple disclosure types, each classified into + primary, secondary, and tertiary categories with a supporting text excerpt. + The full classification list is available at /stocks/taxonomies/vX/disclosures. + """ + url = "/stocks/filings/8-K/vX/disclosures" + return self._paginate( + path=url, + params=self._get_params(self.list_stocks_filings_8k_disclosures, locals()), + result_key="results", + deserializer=Disclosure.from_dict, + raw=raw, + options=options, + ) + + def list_stocks_taxonomies_disclosures( + self, + taxonomy: Optional[str] = None, + taxonomy_any_of: Optional[str] = None, + taxonomy_gt: Optional[str] = None, + taxonomy_gte: Optional[str] = None, + taxonomy_lt: Optional[str] = None, + taxonomy_lte: Optional[str] = None, + primary_category: Optional[str] = None, + primary_category_any_of: Optional[str] = None, + primary_category_gt: Optional[str] = None, + primary_category_gte: Optional[str] = None, + primary_category_lt: Optional[str] = None, + primary_category_lte: Optional[str] = None, + secondary_category: Optional[str] = None, + secondary_category_any_of: Optional[str] = None, + secondary_category_gt: Optional[str] = None, + secondary_category_gte: Optional[str] = None, + secondary_category_lt: Optional[str] = None, + secondary_category_lte: Optional[str] = None, + tertiary_category: Optional[str] = None, + tertiary_category_any_of: Optional[str] = None, + tertiary_category_gt: Optional[str] = None, + tertiary_category_gte: Optional[str] = None, + tertiary_category_lt: Optional[str] = None, + tertiary_category_lte: Optional[str] = None, + limit: Optional[int] = 200, + sort: Optional[Union[str, Sort]] = "taxonomy.desc", + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[DisclosureTaxonomy], HTTPResponse]: + """ + The complete list of 8-K disclosure classifications used in the 8-K + disclosures endpoint. + """ + url = "/stocks/taxonomies/vX/disclosures" + return self._paginate( + path=url, + params=self._get_params(self.list_stocks_taxonomies_disclosures, locals()), + result_key="results", + deserializer=DisclosureTaxonomy.from_dict, + raw=raw, + options=options, + ) + + def list_stocks_filings_10k_sections( + self, + cik: Optional[str] = None, + cik_any_of: Optional[str] = None, + cik_gt: Optional[str] = None, + cik_gte: Optional[str] = None, + cik_lt: Optional[str] = None, + cik_lte: Optional[str] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + section: Optional[str] = None, + section_any_of: Optional[str] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + period_end: Optional[Union[str, date]] = None, + period_end_gt: Optional[Union[str, date]] = None, + period_end_gte: Optional[Union[str, date]] = None, + period_end_lt: Optional[Union[str, date]] = None, + period_end_lte: Optional[Union[str, date]] = None, + limit: Optional[int] = 100, + sort: Optional[Union[str, Sort]] = "period_end.desc", + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[FilingSection], HTTPResponse]: + """ + Get raw text sections from 10-K/10-Q filings (business, risk_factors, etc.). + """ + url = "/stocks/filings/10-K/vX/sections" + return self._paginate( + path=url, + params=self._get_params(self.list_stocks_filings_10k_sections, locals()), + result_key="results", + deserializer=FilingSection.from_dict, + raw=raw, + options=options, + ) + + def list_stocks_filings_8k_text( + self, + cik: Optional[str] = None, + cik_any_of: Optional[str] = None, + cik_gt: Optional[str] = None, + cik_gte: Optional[str] = None, + cik_lt: Optional[str] = None, + cik_lte: Optional[str] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + form_type: Optional[str] = None, + form_type_any_of: Optional[str] = None, + form_type_gt: Optional[str] = None, + form_type_gte: Optional[str] = None, + form_type_lt: Optional[str] = None, + form_type_lte: Optional[str] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + limit: Optional[int] = 100, + sort: Optional[Union[str, Sort]] = "filing_date.desc", + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[Filing8K], HTTPResponse]: + """ + Get parsed 8-K filings (earnings, acquisitions, executive changes, etc.). + """ + url = "/stocks/filings/8-K/vX/text" + return self._paginate( + path=url, + params=self._get_params(self.list_stocks_filings_8k_text, locals()), + result_key="results", + deserializer=Filing8K.from_dict, + raw=raw, + options=options, + ) + + def list_stocks_filings_index( + self, + cik: Optional[str] = None, + cik_any_of: Optional[str] = None, + cik_gt: Optional[str] = None, + cik_gte: Optional[str] = None, + cik_lt: Optional[str] = None, + cik_lte: Optional[str] = None, + ticker: Optional[str] = None, + ticker_any_of: Optional[str] = None, + ticker_gt: Optional[str] = None, + ticker_gte: Optional[str] = None, + ticker_lt: Optional[str] = None, + ticker_lte: Optional[str] = None, + form_type: Optional[str] = None, + form_type_any_of: Optional[str] = None, + form_type_gt: Optional[str] = None, + form_type_gte: Optional[str] = None, + form_type_lt: Optional[str] = None, + form_type_lte: Optional[str] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + limit: Optional[int] = 1000, + sort: Optional[Union[str, Sort]] = "filing_date.desc", + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[FilingIndex], HTTPResponse]: + """ + Get the master index of all SEC filings (10-K, 8-K, 10-Q, S-1, 4, etc.). + """ + url = "/stocks/filings/vX/index" + return self._paginate( + path=url, + params=self._get_params(self.list_stocks_filings_index, locals()), + result_key="results", + deserializer=FilingIndex.from_dict, + raw=raw, + options=options, + ) + + def list_stocks_filings_13f( + self, + filer_cik: Optional[str] = None, + filer_cik_any_of: Optional[str] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + limit: Optional[int] = 100, + sort: Optional[Union[str, Sort]] = "filing_date.desc", + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[Filing13F], HTTPResponse]: + """ + SEC Form 13F filings data showing institutional investment manager holdings. + Form 13F is required to be filed quarterly by institutional investment managers + with at least $100 million in qualifying assets under management. + """ + url = "/stocks/filings/vX/13-F" + + return self._paginate( + path=url, + params=self._get_params(self.list_stocks_filings_13f, locals()), + result_key="results", + deserializer=Filing13F.from_dict, + raw=raw, + options=options, + ) + + def list_stocks_filings_form_3( + self, + issuer_cik: Optional[str] = None, + issuer_cik_any_of: Optional[str] = None, + owner_cik: Optional[str] = None, + owner_cik_any_of: Optional[str] = None, + tickers: Optional[str] = None, + tickers_all_of: Optional[str] = None, + tickers_any_of: Optional[str] = None, + form_type: Optional[str] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + max_ticker: Optional[str] = None, + max_ticker_any_of: Optional[str] = None, + max_ticker_gt: Optional[str] = None, + max_ticker_gte: Optional[str] = None, + max_ticker_lt: Optional[str] = None, + max_ticker_lte: Optional[str] = None, + min_ticker: Optional[str] = None, + min_ticker_any_of: Optional[str] = None, + min_ticker_gt: Optional[str] = None, + min_ticker_gte: Optional[str] = None, + min_ticker_lt: Optional[str] = None, + min_ticker_lte: Optional[str] = None, + limit: Optional[int] = 100, + sort: Optional[Union[str, Sort]] = "filing_date.desc", + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[FilingForm3], HTTPResponse]: + """ + SEC Form 3 filings reporting initial statements of beneficial ownership of securities. + Filed by corporate insiders (directors, officers, and 10%+ shareholders) when they first acquire a position. + """ + url = "/stocks/filings/vX/form-3" + + return self._paginate( + path=url, + params=self._get_params(self.list_stocks_filings_form_3, locals()), + result_key="results", + deserializer=FilingForm3.from_dict, + raw=raw, + options=options, + ) + + def list_stocks_filings_form_4( + self, + issuer_cik: Optional[str] = None, + issuer_cik_any_of: Optional[str] = None, + owner_cik: Optional[str] = None, + owner_cik_any_of: Optional[str] = None, + tickers: Optional[str] = None, + tickers_all_of: Optional[str] = None, + tickers_any_of: Optional[str] = None, + form_type: Optional[str] = None, + transaction_code: Optional[str] = None, + filing_date: Optional[Union[str, date]] = None, + filing_date_gt: Optional[Union[str, date]] = None, + filing_date_gte: Optional[Union[str, date]] = None, + filing_date_lt: Optional[Union[str, date]] = None, + filing_date_lte: Optional[Union[str, date]] = None, + max_ticker: Optional[str] = None, + max_ticker_any_of: Optional[str] = None, + max_ticker_gt: Optional[str] = None, + max_ticker_gte: Optional[str] = None, + max_ticker_lt: Optional[str] = None, + max_ticker_lte: Optional[str] = None, + min_ticker: Optional[str] = None, + min_ticker_any_of: Optional[str] = None, + min_ticker_gt: Optional[str] = None, + min_ticker_gte: Optional[str] = None, + min_ticker_lt: Optional[str] = None, + min_ticker_lte: Optional[str] = None, + limit: Optional[int] = 100, + sort: Optional[Union[str, Sort]] = "filing_date.desc", + params: Optional[Dict[str, Any]] = None, + raw: bool = False, + options: Optional[RequestOptionBuilder] = None, + ) -> Union[Iterator[FilingForm4], HTTPResponse]: + """ + SEC Form 4 filings reporting changes in beneficial ownership of securities. + Filed by corporate insiders (directors, officers, and 10%+ shareholders) within two business days of a transaction. + """ + url = "/stocks/filings/vX/form-4" + + return self._paginate( + path=url, + params=self._get_params(self.list_stocks_filings_form_4, locals()), + result_key="results", + deserializer=FilingForm4.from_dict, + raw=raw, options=options, ) diff --git a/massive/websocket/models/models.py b/massive/websocket/models/models.py index c0903530..cc3d3c16 100644 --- a/massive/websocket/models/models.py +++ b/massive/websocket/models/models.py @@ -22,6 +22,8 @@ class EquityAgg: start_timestamp: Optional[int] = None end_timestamp: Optional[int] = None otc: Optional[bool] = None + fractional_volume: Optional[str] = None + fractional_accumulated_volume: Optional[str] = None @staticmethod def from_dict(d): @@ -41,6 +43,8 @@ def from_dict(d): d.get("s", None), d.get("e", None), d.get("otc", None), + d.get("dv", None), + d.get("dav", None), ) @@ -86,6 +90,7 @@ class EquityTrade: tape: Optional[int] = None price: Optional[float] = None size: Optional[int] = None + fractional_shares: Optional[str] = None conditions: Optional[List[int]] = None timestamp: Optional[int] = None sequence_number: Optional[int] = None @@ -102,6 +107,7 @@ def from_dict(d): d.get("z", None), d.get("p", None), d.get("s", None), + d.get("ds", None), d.get("c", None), d.get("t", None), d.get("q", None), diff --git a/poetry.lock b/poetry.lock index e60b9381..8cb653a5 100644 --- a/poetry.lock +++ b/poetry.lock @@ -94,14 +94,14 @@ uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "certifi" -version = "2026.1.4" +version = "2026.2.25" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.7" groups = ["main", "dev"] files = [ - {file = "certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c"}, - {file = "certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120"}, + {file = "certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa"}, + {file = "certifi-2026.2.25.tar.gz", hash = "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7"}, ] [[package]] @@ -269,6 +269,7 @@ description = "Mypyc runtime library" optional = false python-versions = ">=3.9" groups = ["dev"] +markers = "platform_python_implementation != \"PyPy\"" files = [ {file = "librt-0.7.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0090f146caa593f47e641307bd0bef778b76629b1d7a5bec95d3a83ed49d49de"}, {file = "librt-0.7.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c44321bc013cf4b41169e463a2c441412497cea44dbf79eee0ccad8104d05b7b"}, @@ -400,54 +401,54 @@ files = [ [[package]] name = "mypy" -version = "1.19.0" +version = "1.19.1" description = "Optional static typing for Python" optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "mypy-1.19.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6148ede033982a8c5ca1143de34c71836a09f105068aaa8b7d5edab2b053e6c8"}, - {file = "mypy-1.19.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a9ac09e52bb0f7fb912f5d2a783345c72441a08ef56ce3e17c1752af36340a39"}, - {file = "mypy-1.19.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:11f7254c15ab3f8ed68f8e8f5cbe88757848df793e31c36aaa4d4f9783fd08ab"}, - {file = "mypy-1.19.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:318ba74f75899b0e78b847d8c50821e4c9637c79d9a59680fc1259f29338cb3e"}, - {file = "mypy-1.19.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cf7d84f497f78b682edd407f14a7b6e1a2212b433eedb054e2081380b7395aa3"}, - {file = "mypy-1.19.0-cp310-cp310-win_amd64.whl", hash = "sha256:c3385246593ac2b97f155a0e9639be906e73534630f663747c71908dfbf26134"}, - {file = "mypy-1.19.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a31e4c28e8ddb042c84c5e977e28a21195d086aaffaf08b016b78e19c9ef8106"}, - {file = "mypy-1.19.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:34ec1ac66d31644f194b7c163d7f8b8434f1b49719d403a5d26c87fff7e913f7"}, - {file = "mypy-1.19.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cb64b0ba5980466a0f3f9990d1c582bcab8db12e29815ecb57f1408d99b4bff7"}, - {file = "mypy-1.19.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:120cffe120cca5c23c03c77f84abc0c14c5d2e03736f6c312480020082f1994b"}, - {file = "mypy-1.19.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7a500ab5c444268a70565e374fc803972bfd1f09545b13418a5174e29883dab7"}, - {file = "mypy-1.19.0-cp311-cp311-win_amd64.whl", hash = "sha256:c14a98bc63fd867530e8ec82f217dae29d0550c86e70debc9667fff1ec83284e"}, - {file = "mypy-1.19.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0fb3115cb8fa7c5f887c8a8d81ccdcb94cff334684980d847e5a62e926910e1d"}, - {file = "mypy-1.19.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f3e19e3b897562276bb331074d64c076dbdd3e79213f36eed4e592272dabd760"}, - {file = "mypy-1.19.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b9d491295825182fba01b6ffe2c6fe4e5a49dbf4e2bb4d1217b6ced3b4797bc6"}, - {file = "mypy-1.19.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6016c52ab209919b46169651b362068f632efcd5eb8ef9d1735f6f86da7853b2"}, - {file = "mypy-1.19.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f188dcf16483b3e59f9278c4ed939ec0254aa8a60e8fc100648d9ab5ee95a431"}, - {file = "mypy-1.19.0-cp312-cp312-win_amd64.whl", hash = "sha256:0e3c3d1e1d62e678c339e7ade72746a9e0325de42cd2cccc51616c7b2ed1a018"}, - {file = "mypy-1.19.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7686ed65dbabd24d20066f3115018d2dce030d8fa9db01aa9f0a59b6813e9f9e"}, - {file = "mypy-1.19.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:fd4a985b2e32f23bead72e2fb4bbe5d6aceee176be471243bd831d5b2644672d"}, - {file = "mypy-1.19.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fc51a5b864f73a3a182584b1ac75c404396a17eced54341629d8bdcb644a5bba"}, - {file = "mypy-1.19.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:37af5166f9475872034b56c5efdcf65ee25394e9e1d172907b84577120714364"}, - {file = "mypy-1.19.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:510c014b722308c9bd377993bcbf9a07d7e0692e5fa8fc70e639c1eb19fc6bee"}, - {file = "mypy-1.19.0-cp313-cp313-win_amd64.whl", hash = "sha256:cabbee74f29aa9cd3b444ec2f1e4fa5a9d0d746ce7567a6a609e224429781f53"}, - {file = "mypy-1.19.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:f2e36bed3c6d9b5f35d28b63ca4b727cb0228e480826ffc8953d1892ddc8999d"}, - {file = "mypy-1.19.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a18d8abdda14035c5718acb748faec09571432811af129bf0d9e7b2d6699bf18"}, - {file = "mypy-1.19.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f75e60aca3723a23511948539b0d7ed514dda194bc3755eae0bfc7a6b4887aa7"}, - {file = "mypy-1.19.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8f44f2ae3c58421ee05fe609160343c25f70e3967f6e32792b5a78006a9d850f"}, - {file = "mypy-1.19.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:63ea6a00e4bd6822adbfc75b02ab3653a17c02c4347f5bb0cf1d5b9df3a05835"}, - {file = "mypy-1.19.0-cp314-cp314-win_amd64.whl", hash = "sha256:3ad925b14a0bb99821ff6f734553294aa6a3440a8cb082fe1f5b84dfb662afb1"}, - {file = "mypy-1.19.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0dde5cb375cb94deff0d4b548b993bec52859d1651e073d63a1386d392a95495"}, - {file = "mypy-1.19.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1cf9c59398db1c68a134b0b5354a09a1e124523f00bacd68e553b8bd16ff3299"}, - {file = "mypy-1.19.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3210d87b30e6af9c8faed61be2642fcbe60ef77cec64fa1ef810a630a4cf671c"}, - {file = "mypy-1.19.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e2c1101ab41d01303103ab6ef82cbbfedb81c1a060c868fa7cc013d573d37ab5"}, - {file = "mypy-1.19.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:0ea4fd21bb48f0da49e6d3b37ef6bd7e8228b9fe41bbf4d80d9364d11adbd43c"}, - {file = "mypy-1.19.0-cp39-cp39-win_amd64.whl", hash = "sha256:16f76ff3f3fd8137aadf593cb4607d82634fca675e8211ad75c43d86033ee6c6"}, - {file = "mypy-1.19.0-py3-none-any.whl", hash = "sha256:0c01c99d626380752e527d5ce8e69ffbba2046eb8a060db0329690849cf9b6f9"}, - {file = "mypy-1.19.0.tar.gz", hash = "sha256:f6b874ca77f733222641e5c46e4711648c4037ea13646fd0cdc814c2eaec2528"}, + {file = "mypy-1.19.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5f05aa3d375b385734388e844bc01733bd33c644ab48e9684faa54e5389775ec"}, + {file = "mypy-1.19.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:022ea7279374af1a5d78dfcab853fe6a536eebfda4b59deab53cd21f6cd9f00b"}, + {file = "mypy-1.19.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee4c11e460685c3e0c64a4c5de82ae143622410950d6be863303a1c4ba0e36d6"}, + {file = "mypy-1.19.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de759aafbae8763283b2ee5869c7255391fbc4de3ff171f8f030b5ec48381b74"}, + {file = "mypy-1.19.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ab43590f9cd5108f41aacf9fca31841142c786827a74ab7cc8a2eacb634e09a1"}, + {file = "mypy-1.19.1-cp310-cp310-win_amd64.whl", hash = "sha256:2899753e2f61e571b3971747e302d5f420c3fd09650e1951e99f823bc3089dac"}, + {file = "mypy-1.19.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d8dfc6ab58ca7dda47d9237349157500468e404b17213d44fc1cb77bce532288"}, + {file = "mypy-1.19.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e3f276d8493c3c97930e354b2595a44a21348b320d859fb4a2b9f66da9ed27ab"}, + {file = "mypy-1.19.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2abb24cf3f17864770d18d673c85235ba52456b36a06b6afc1e07c1fdcd3d0e6"}, + {file = "mypy-1.19.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a009ffa5a621762d0c926a078c2d639104becab69e79538a494bcccb62cc0331"}, + {file = "mypy-1.19.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f7cee03c9a2e2ee26ec07479f38ea9c884e301d42c6d43a19d20fb014e3ba925"}, + {file = "mypy-1.19.1-cp311-cp311-win_amd64.whl", hash = "sha256:4b84a7a18f41e167f7995200a1d07a4a6810e89d29859df936f1c3923d263042"}, + {file = "mypy-1.19.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a8174a03289288c1f6c46d55cef02379b478bfbc8e358e02047487cad44c6ca1"}, + {file = "mypy-1.19.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ffcebe56eb09ff0c0885e750036a095e23793ba6c2e894e7e63f6d89ad51f22e"}, + {file = "mypy-1.19.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b64d987153888790bcdb03a6473d321820597ab8dd9243b27a92153c4fa50fd2"}, + {file = "mypy-1.19.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c35d298c2c4bba75feb2195655dfea8124d855dfd7343bf8b8c055421eaf0cf8"}, + {file = "mypy-1.19.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:34c81968774648ab5ac09c29a375fdede03ba253f8f8287847bd480782f73a6a"}, + {file = "mypy-1.19.1-cp312-cp312-win_amd64.whl", hash = "sha256:b10e7c2cd7870ba4ad9b2d8a6102eb5ffc1f16ca35e3de6bfa390c1113029d13"}, + {file = "mypy-1.19.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e3157c7594ff2ef1634ee058aafc56a82db665c9438fd41b390f3bde1ab12250"}, + {file = "mypy-1.19.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bdb12f69bcc02700c2b47e070238f42cb87f18c0bc1fc4cdb4fb2bc5fd7a3b8b"}, + {file = "mypy-1.19.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f859fb09d9583a985be9a493d5cfc5515b56b08f7447759a0c5deaf68d80506e"}, + {file = "mypy-1.19.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c9a6538e0415310aad77cb94004ca6482330fece18036b5f360b62c45814c4ef"}, + {file = "mypy-1.19.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:da4869fc5e7f62a88f3fe0b5c919d1d9f7ea3cef92d3689de2823fd27e40aa75"}, + {file = "mypy-1.19.1-cp313-cp313-win_amd64.whl", hash = "sha256:016f2246209095e8eda7538944daa1d60e1e8134d98983b9fc1e92c1fc0cb8dd"}, + {file = "mypy-1.19.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:06e6170bd5836770e8104c8fdd58e5e725cfeb309f0a6c681a811f557e97eac1"}, + {file = "mypy-1.19.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:804bd67b8054a85447c8954215a906d6eff9cabeabe493fb6334b24f4bfff718"}, + {file = "mypy-1.19.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:21761006a7f497cb0d4de3d8ef4ca70532256688b0523eee02baf9eec895e27b"}, + {file = "mypy-1.19.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:28902ee51f12e0f19e1e16fbe2f8f06b6637f482c459dd393efddd0ec7f82045"}, + {file = "mypy-1.19.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:481daf36a4c443332e2ae9c137dfee878fcea781a2e3f895d54bd3002a900957"}, + {file = "mypy-1.19.1-cp314-cp314-win_amd64.whl", hash = "sha256:8bb5c6f6d043655e055be9b542aa5f3bdd30e4f3589163e85f93f3640060509f"}, + {file = "mypy-1.19.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7bcfc336a03a1aaa26dfce9fff3e287a3ba99872a157561cbfcebe67c13308e3"}, + {file = "mypy-1.19.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b7951a701c07ea584c4fe327834b92a30825514c868b1f69c30445093fdd9d5a"}, + {file = "mypy-1.19.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b13cfdd6c87fc3efb69ea4ec18ef79c74c3f98b4e5498ca9b85ab3b2c2329a67"}, + {file = "mypy-1.19.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4f28f99c824ecebcdaa2e55d82953e38ff60ee5ec938476796636b86afa3956e"}, + {file = "mypy-1.19.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c608937067d2fc5a4dd1a5ce92fd9e1398691b8c5d012d66e1ddd430e9244376"}, + {file = "mypy-1.19.1-cp39-cp39-win_amd64.whl", hash = "sha256:409088884802d511ee52ca067707b90c883426bd95514e8cfda8281dc2effe24"}, + {file = "mypy-1.19.1-py3-none-any.whl", hash = "sha256:f1235f5ea01b7db5468d53ece6aaddf1ad0b88d9e7462b86ef96fe04995d7247"}, + {file = "mypy-1.19.1.tar.gz", hash = "sha256:19d88bb05303fe63f71dd2c6270daca27cb9401c4ca8255fe50d1d920e0eb9ba"}, ] [package.dependencies] -librt = ">=0.6.2" +librt = {version = ">=0.6.2", markers = "platform_python_implementation != \"PyPy\""} mypy_extensions = ">=1.0.0" pathspec = ">=0.9.0" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} @@ -643,14 +644,14 @@ xmltodict = ">=0.11.0" [[package]] name = "pygments" -version = "2.19.2" +version = "2.20.0" description = "Pygments is a syntax highlighting package written in Python." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b"}, - {file = "pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"}, + {file = "pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176"}, + {file = "pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f"}, ] [package.extras] @@ -793,19 +794,19 @@ testing = ["covdefaults (>=2.3)", "coverage (>=7.4.4)", "defusedxml (>=0.7.1)", [[package]] name = "sphinx-rtd-theme" -version = "3.0.2" +version = "3.1.0" description = "Read the Docs theme for Sphinx" optional = false python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "sphinx_rtd_theme-3.0.2-py2.py3-none-any.whl", hash = "sha256:422ccc750c3a3a311de4ae327e82affdaf59eb695ba4936538552f3b00f4ee13"}, - {file = "sphinx_rtd_theme-3.0.2.tar.gz", hash = "sha256:b7457bc25dda723b20b086a670b9953c859eab60a2a03ee8eb2bb23e176e5f85"}, + {file = "sphinx_rtd_theme-3.1.0-py2.py3-none-any.whl", hash = "sha256:1785824ae8e6632060490f67cf3a72d404a85d2d9fc26bce3619944de5682b89"}, + {file = "sphinx_rtd_theme-3.1.0.tar.gz", hash = "sha256:b44276f2c276e909239a4f6c955aa667aaafeb78597923b1c60babc76db78e4c"}, ] [package.dependencies] -docutils = ">0.18,<0.22" -sphinx = ">=6,<9" +docutils = ">0.18,<0.23" +sphinx = ">=6,<10" sphinxcontrib-jquery = ">=4,<5" [package.extras] @@ -949,14 +950,14 @@ files = [ [[package]] name = "types-setuptools" -version = "80.9.0.20250822" +version = "81.0.0.20260209" description = "Typing stubs for setuptools" optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "types_setuptools-80.9.0.20250822-py3-none-any.whl", hash = "sha256:53bf881cb9d7e46ed12c76ef76c0aaf28cfe6211d3fab12e0b83620b1a8642c3"}, - {file = "types_setuptools-80.9.0.20250822.tar.gz", hash = "sha256:070ea7716968ec67a84c7f7768d9952ff24d28b65b6594797a464f1b3066f965"}, + {file = "types_setuptools-81.0.0.20260209-py3-none-any.whl", hash = "sha256:4facf71e3f953f8f5ac0020cd6c1b5e493aaff0183e85830bc34870b6abf8475"}, + {file = "types_setuptools-81.0.0.20260209.tar.gz", hash = "sha256:2c2eb64499b41b672c387f6f45678a28d20a143a81b45a5c77acbfd4da0df3e1"}, ] [[package]] @@ -985,14 +986,14 @@ files = [ [[package]] name = "urllib3" -version = "2.6.1" +version = "2.6.3" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.9" groups = ["main", "dev"] files = [ - {file = "urllib3-2.6.1-py3-none-any.whl", hash = "sha256:e67d06fe947c36a7ca39f4994b08d73922d40e6cca949907be05efa6fd75110b"}, - {file = "urllib3-2.6.1.tar.gz", hash = "sha256:5379eb6e1aba4088bae84f8242960017ec8d8e3decf30480b3a1abdaa9671a3f"}, + {file = "urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4"}, + {file = "urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed"}, ] [package.extras] @@ -1116,4 +1117,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = "^3.9" -content-hash = "503cc42b24ba50c2442440839484054914bdd38c3174268a948d3ba2679e528a" +content-hash = "859fb753010770932bb13116107b08bf52ef64a130954852216b405cc219fc21" diff --git a/pyproject.toml b/pyproject.toml index 22fd7672..058444af 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,11 +34,11 @@ black = "^24.8.0" mypy = "^1.19" types-urllib3 = "^1.26.25" Sphinx = "^7.4.7" -sphinx-rtd-theme = "^3.0.2" +sphinx-rtd-theme = "^3.1.0" # keep this in sync with docs/requirements.txt for readthedocs.org sphinx-autodoc-typehints = "^2.3.0" types-certifi = "^2021.10.8" -types-setuptools = "^80.9.0" +types-setuptools = "^81.0.0" pook = "^2.1.4" orjson = "^3.11.5"