diff --git a/massive/rest/economy.py b/massive/rest/economy.py index f8d58272..4c4b251f 100644 --- a/massive/rest/economy.py +++ b/massive/rest/economy.py @@ -8,6 +8,8 @@ TreasuryYield, FedInflationExpectations, FedLaborMarket, + EUMerchantAggregate, + EUMerchantHierarchy, ) from .models.common import Sort, Order from .models.request import RequestOptionBuilder @@ -168,3 +170,103 @@ def list_labor_market_indicators( 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/models/economy.py b/massive/rest/models/economy.py index e6ae8d4f..97386235 100644 --- a/massive/rest/models/economy.py +++ b/massive/rest/models/economy.py @@ -104,3 +104,126 @@ def from_dict(d): 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"), + )