import calendar
import pandas as pd
from IPython.display import Markdown, display
from tulip.core.collection import TulipCollection
from tulip.core import merge_collections
from tulip.data.bloomberg import BloombergClient as bb
from tulip.data.haver import (
get_series as get_series_from_haver,
get_collection as get_collection_from_haver,
)
from tulip.data.fred import get_series_from_fred
from tulip.data.gs import GSClient as gs
from tulip.data.bloomberg.collections import US_WEEKLY_ACTIVITY
from tulip.plots import plot_line, plot_lines, plot_bar
from tulip.genai import iris
from tulip_mania.columns import columns
from tulip_mania.notebook_related import notebook_updated, display_two_chartsUnited States¶
Comprehensive analysis of U.S. economic conditions
# ========================================
# PARAMETERS & DATA FETCHING
# ========================================
# Country identifiers
ctry_name = "United States"
ctry_iso3 = "USA"
ctry_iso2 = "US"
ccy = "USD"
goldman_ctry_id = "US"
bloomberg_ctry_prefix = "US"
# ----------------------------------------
# GROWTH DATA
# ----------------------------------------
# Weekly Activity Indicators
weekly_series_collection = []
weekly_series_collection.append(get_series_from_fred("WEI"))
for k, v in US_WEEKLY_ACTIVITY.items():
weekly_series_collection.append(bb.get_series(v))
cc = get_series_from_fred("CCLACBW027SBOG")
cc.ts = cc.ts.pct_change() * 12 * 100
cc.info.quote_units = "%"
cc.info.title = "Credit Card Loans, MoM, ann."
weekly_series_collection.append(cc)
us_weekly_dashboard = TulipCollection(weekly_series_collection)
us_weekly_dashboard[1].title = "Same Store Sales (Redbook)"
us_weekly_dashboard[2].title = "Initial Jobless Claims"
us_weekly_dashboard[3].title = "Initial Jobless Claims: Federal Employees"
us_weekly_dashboard[6].title = "Railroad Total Traffic"
us_weekly_dashboard["INJCJC Index"].good_is = -1
us_weekly_dashboard["INJCUIFE Index"].good_is = -1
us_weekly_dashboard["CCLACBW027SBOG"].good_is = -1
# Activity/Nowcast Indicators
activity_indicators_collection = TulipCollection(
[
bb.get_series("BENWUSGC Index"),
bb.get_series("CLEVFGDP Index"),
get_series_from_fred("GDPNOW"),
get_series_from_fred("STLENI"),
bb.get_series("USBBLEAD Index"),
]
)
activity_indicators_collection.good_is = {
"BENWUSGC Index": 1,
"CLEVFGDP Index": 1,
"GDPNOW": 1,
"STLENI": 1,
"USBBLEAD Index": 1,
}
# Retail Sales
retail_sales = bb.get_series("RSTAMOM Index")
retail_sales.info.title = "Retail Sales MoM"
# Consumer Spend
consumer_spend_high_freq = bb.get_series("BSMCST91YOY Index")
consumer_spend_high_freq.info.title = "US Consumer Spend YOY"
# PMIs
pmi_series = TulipCollection(
[
bb.get_series("MPMIUSCA Index"),
bb.get_series("MPMIUSSA Index"),
bb.get_series("NAPMNMI Index"),
bb.get_series("NAPMNPRC Index"),
bb.get_series("NAPMNNO Index"),
]
)
pmi_series[0].title = "S&P US Composite PMI"
pmi_series[1].title = "S&P US Services PMI"
pmi_series[2].title = "ISM Manuf. PMI"
pmi_series[3].title = "ISM Manuf. Prices paid"
pmi_series[4].title = "ISM Manuf. New orders"
# Leading Indicators
leading_indicators = get_collection_from_haver(
{
"Average Weekly Hours": "LRMANUA@USECON",
"ISM Vendor Deliveries": "NAPMVDI@USECON",
"New Manufacturing Orders": "NMONC@USECON",
"Housing Permits": "HPT@USECON",
"10Y-2Y Treasury Spread": "F10FED@USECON",
"S&P 500": "SP500@USECON",
"M2 Money Supply": "FM2C@USECON",
"Consumer Expectations": "CEXP@USECON",
}
)
leading_indicators.good_is = {
"LRMANUA@USECON": 1,
"NAPMVDI@USECON": 1,
"NMONC@USECON": 1,
"HPT@USECON": 1,
"F10FED@USECON": 1,
"SP500@USECON": 1,
"FM2C@USECON": 1,
"CEXP@USECON": 1,
}
# ----------------------------------------
# PRICES DATA
# ----------------------------------------
# Core Inflation
inflation_titles = {
"CPI YOY Index": "CPI YoY",
"PCE CYOY Index": "PCE Core YoY",
"CPI CHNG Index": "CPI MoM",
"CPI XYOY Index": "CPI Ex-Food & Energy YoY",
}
inflation = bb.create_collection(list(inflation_titles.keys()))
for i, k in enumerate(inflation_titles.values()):
inflation[i].info.title = k
inflation.good_is = -1
# Inflation Nowcasts
inflation_nowcasts = bb.create_collection(
[
"CLEVCPYC Index",
"CLEVCPMC Index",
"BENWUSOM Index",
"BENWUSCM Index",
"TRUFUSYY Index",
]
)
# Inflation Forecasts
inflation_forecasts = get_collection_from_haver(
{
"1Y Inflation Expectations": "CINF1@USECON",
"5Y Inflation Expectations": "CINF5@USECON",
"2Y Breakeven": "CIE2P@USECON",
"2Y Swap": "CIE2M@USECON",
}
)
inflation_forecasts.good_is = -1
# Wages
wages = get_collection_from_haver(
{
"Private Avg Hourly Earnings": "LEPRIVA@USECON",
"Goods Avg Hourly Earnings": "LEGOODA@USECON",
"Services Avg Hourly Earnings": "LEPSRVA@USECON",
}
).apply("yoy")
# Rents
rent_haver = get_collection_from_haver(
{
"New Tenant Rent": "CFNTRR@USECON",
"All Tenant Rent": "CFATRR@USECON",
}
)
zillow_rent = bb.get_series("ZRIOAYOY Index")
# ----------------------------------------
# EMPLOYMENT DATA
# ----------------------------------------
# Main Employment Figures
main_employment_figures = get_collection_from_haver(
{
"Unemployment rate": "LR@USECON",
"Nonfarm payroll employment": "LANAGRD@USECON",
"Labor force participation rate": "LP@USECON",
"Workers employed part-time for economic reasons": "LEPTE@USECON",
"U-6 measure of labor underutilization": "MLU6@USECON",
"Average hourly earnings": "LETPRIVA@USECON",
"Job openings rate": "LJJTPA@USECON",
"Hires rate": "LJHTPA@USECON",
"Quits rate": "LJQTPA@USECON",
"Layoffs and discharges rate": "LJLTPA@USECON",
}
)
main_employment_figures.good_is = {
"LR@USECON": -1,
"LANAGRD@USECON": 1,
"LP@USECON": 1,
"LEPTE@USECON": -1,
"MLU6@USECON": -1,
"LETPRIVA@USECON": 1,
"LJJTPA@USECON": 1,
"LJHTPA@USECON": 1,
"LJQTPA@USECON": -1,
"LJLTPA@USECON": -1,
}
other_employment_figures = get_collection_from_haver(
{
"Long-term unemployment": "LUT27P@USECON",
"Marginally attached workers": "LHWSAN@USECON",
}
)
other_employment_figures.good_is = -1
combined_employment_figures = main_employment_figures.combine(other_employment_figures)
# Claims
claims = get_collection_from_haver(
{
"US Initial Jobless Claims": "E111UCS@INTWKLY",
"US Continuing Jobless Claims": "E111UIS@INTWKLY",
}
)
claims.good_is = -1
# NFP
nfp_collection = bb.create_collection(
{
"Nonfarm Payrolls ADP": "ADP CHNG Index",
"Nonfarm Payrolls Net Change SA": "NFP TCH Index",
"Nonfarm Payrolls Private Chng SA": "NFP PCH Index",
"Nonfarm Payrolls Goods MoM": "NFP GPCH Index",
}
)
# JOLTS
jolts = bb.create_collection(
[
"JOLTTOTL Index",
"JOLTOPEN Index",
"JLTSQUIS Index",
"JOLTQUIS Index",
"JLTSLAYS Index",
"JOLTLAYS Index",
]
)
for i, k in enumerate(
[
"Job Openings Level",
"Job Openings Rate",
"Quits Level",
"Quits Rate",
"Layoffs Level",
"Layoffs Rate",
]
):
jolts[i].info.title = k
jolts.good_is = {
"JOLTTOTL Index": 1,
"JOLTOPEN Index": 1,
"JLTSQUIS Index": -1,
"JOLTQUIS Index": -1,
"JLTSLAYS Index": 1,
"JOLTLAYS Index": 1,
}
# Unemployment measures
unemployment_fred_tickers = {
"Unemployment (U2)": "U2RATE",
"Main Unemployment Measure (U3)": "UNRATE",
"Unemployment (U4)": "U4RATE",
"Unemployment (U6)": "U6RATE",
"Unemployment Rate - 16-24 Yrs.": "LNS14024887",
"Unemployment Rate - College Graduates": "CGBD2534",
"Unemployment Rate - High School Graduates": "LNS14027660",
"Continued Claims": "CCSA",
"Permanent Job Losers": "LNS13026638",
}
unemployment_indicators = []
for k, v in unemployment_fred_tickers.items():
ts = get_series_from_fred(v, good_is=-1)
ts.title = k
unemployment_indicators.append(ts)
unemployment_indicators.append(get_series_from_haver("LMN@USECON"))
unemployment_indicators.append(get_series_from_haver("LMXN@USECON"))
unemployment_collection = TulipCollection(unemployment_indicators)
unemployment_collection.good_is = {
"U2RATE": -1,
"UNRATE": -1,
"U4RATE": -1,
"U6RATE": -1,
"LNS14024887": -1,
"CGBD2534": -1,
"LNS14027660": -1,
"CCSA": -1,
"LNS13026638": -1,
"LMN@USECON": -1,
"LMXN@USECON": -1,
}
# FOMC Projections
fomc_projections = []
for k, v in {
"Unemployment Rate Projection Median": "UNRATEMD",
"Unemployment Rate Projection Central Tendency": "UNRATECTM",
}.items():
ts = get_series_from_fred(v, good_is=-1)
ts.title = k
fomc_projections.append(ts)
fomc_projections_collection = TulipCollection(fomc_projections)
# True Unemployment
true_ue_collection = bb.create_collection(
{"True UE": "LISEDHDL Index", "Official UE": "USURTOT Index"}
)
true_ue_collection.good_is = -1
# WARN Notices
warn_notices = get_collection_from_haver(
{
"Implied Layoffs": "WARNW@USECON",
"WARN Factor": "WARNF@USECON",
}
)
warn_notices.good_is = {"WARNW@USECON": -1, "WARNF@USECON": -1}
# Alternative Employment Data
alternative_employment_tickers = {
"LinkUp Weekly Active Jobs": "LKUPUAJW Index",
"LinkUp Weekly Created Jobs": "LKUPCJCW Index",
"LinkUp Weekly Deleted Jobs": "LKUPDJCW Index",
"LinkUp Avg Time to Fill": "LKUPCDRW Index",
"LinkUp Monthly Active Jobs": "LKUPUAJM Index",
"LinkUp Monthly Created Jobs": "LKUPCJCM Index",
"LinkUp Monthly Deleted Jobs": "LKUPDJCM Index",
"Challenger Total Job Cuts": "CHALTOTL Index",
"Challenger Govt Job Cuts": "CHALGOVT Index",
"Indeed Job Postings SA": "INDDUOIS Index",
"Indeed Job Postings NSA": "INDDUOIN Index",
"Indeed New Postings SA": "INDDUNIS Index",
"Indeed Software Dev Postings": "INDDSFTW Index",
"Homebase Hours Worked": "USHMHWTO Index",
"Homebase Employees Working": "USHMEWTO Index",
}
alternative_employment = bb.create_collection(alternative_employment_tickers)
alternative_employment.good_is = {
"LKUPUAJW Index": 1,
"LKUPCJCW Index": 1,
"LKUPDJCW Index": -1,
"LKUPCDRW Index": 1,
"LKUPUAJM Index": 1,
"LKUPCJCM Index": 1,
"LKUPDJCM Index": -1,
"CHALTOTL Index": -1,
"CHALGOVT Index": -1,
"INDDUOIS Index": 1,
"INDDUOIN Index": 1,
"INDDUNIS Index": 1,
"INDDSFTW Index": 1,
"USHMHWTO Index": 1,
"USHMEWTO Index": 1,
}# ========================================
# MAIN SUMMARY
# ========================================
growth_collection = merge_collections(
us_weekly_dashboard,
activity_indicators_collection,
pmi_series,
leading_indicators,
)
inflation_collection = merge_collections(
inflation,
inflation_nowcasts,
inflation_forecasts,
)
unemployment_and_slack_collection = merge_collections(
main_employment_figures,
claims,
jolts,
unemployment_collection,
)
# TODO: Add fiscal data collection
# fiscal_collection = merge_collections(...)
# TODO: Add other/external sector data
# other_collecaion = merge_collections(...)
country_collection = merge_collections(
growth_collection,
inflation_collection,
unemployment_and_slack_collection,
)
overall_summary = iris.summarize(
country_collection, "Highlight recent developments that could matter for markets"
)
overall_summary.html()1. Growth: Activity & Output¶
1.1 High Frequency (Weekly) Indicators¶
us_weekly_dashboard_response = iris.summarize(
us_weekly_dashboard,
"These are weekly economic indicators of varying importance.",
bullets=4,
)
us_weekly_dashboard_response.html()us_weekly_dashboard.dashboard.table()us_weekly_dashboard.dashboard.plots(years_limit=3, mma=12, show_0=True, use_gl=True)1.2 Growth Nowcasts & Real-Time Indicators¶
Current Activity Indicator¶
Based on Goldman’s indicator
cai_series_soft_vs_hard = gs.get_CAI_series(
geographyId=ctry_iso2,
metricName=[
"CAI_HEADLINE",
"CAI_CONTRIBUTION_TYPE_HARD",
"CAI_CONTRIBUTION_TYPE_SOFT",
],
startDate="1980-01-01",
)
cai_series_soft_vs_hard = cai_series_soft_vs_hard.set_index("metricName", append=True)[
"metricValue"
].unstack("metricName")
cai_series_soft_vs_hard.columns = ["Hard", "Soft", "Headline"]
cai_plot = plot_lines(
cai_series_soft_vs_hard,
show_0=True,
title=f"<b>{ctry_iso2} Current Activity Indicator</b> Updated: {pd.Timestamp.today().strftime('%Y-%m-%d')}",
years_limit=3,
)
cai_plot.show()Bloomberg nowcast, GDPNow and St Louis Fed Nowcast¶
activity_indicators_collection.dashboard.table()# activity_indicators_collection.dashboard.plots(
# years_limit=3, show_0=True, tick_suffix="%"
# )1.3 Retail Sales & Consumer Activity¶
retail_sales.plot(years_limit=2, tick_suffix="%")US Consumer Spend YOY¶
Trailing 91 Day aggregation of Bloomberg Second Measure US Consumer Spend Index daily data. The Bloomberg Second Measure US Consumer Spend Index presents a holistic view of consumer spending as seen through the lens of transaction data. Bloomberg Second Measure’s transaction data analytics take into account billions of U.S. consumers’ credit card and debit card transactions derived from a panel of 20+ million consumers. The index tracks aggregated U.S. consumer spending and provides the ability to drill down into spending by sector. The data is updated daily and published on a 7-day lag.
consumer_spend_high_freq.plot(years_limit=2, tick_suffix="%", source="Bloomberg")1.4 Business Activity Surveys (PMIs)¶
pmi_series.dashboard.table()# pmi_series.dashboard.plots(years_limit=3)1.5 Other Leading Indicators¶
leading_indicators.dashboard.table()# leading_indicators.dashboard.plots(years_limit=10, mma=12)2. Prices: Inflation & Wages¶
2.1 Headline & Core Inflation¶
inflation.dashboard.table()inflation_df = inflation.df
inflation_df.columns = inflation.summary.index
inflation_df["CPI MoM"] *= 12
fig = plot_lines(
inflation_df.rename(columns={"CPI MoM": "CPI MoM ann."}),
years_limit=3,
tick_suffix="%",
title="<b>United States Inflation</b>",
use_gl=True,
)
fig.update_traces(line=dict(width=0.5), selector=dict(name="CPI MoM ann."))
fig.add_hline(
y=2, line_dash="dash", line_color="gray", line_width=2, annotation_text="2% Target"
)2.2 Inflation Nowcasts¶
# inflation_nowcasts.dashboard.plots()2.3 Inflation Expectations & Forecasts¶
inflation_forecasts.dashboard.table()# inflation_forecasts.dashboard.plots(years_limit=3)2.4 Wage Growth & Labor Costs¶
wages.dashboard.table()# wages.dashboard.plots(years_limit=3, tick_suffix="%")2.5 Rents¶
There has been an update to the methodology. Probably what is behind the drop.
https://
rent_haver.dashboard.plots()fig = zillow_rent.plot(years_limit=5, tick_suffix="%", show_0=True)
fig = fig.add_hline(2)
fig.show()3. Slack: Output Gap & Capacity Utilization¶
5. Financial Conditions¶
6. Fiscal Conditions¶
from tulip_mania.notebook_related import notebook_updated
notebook_updated()