import pandas as pd
from IPython.display import Markdown, HTML
from tulip.data.bloomberg import BloombergClient as bb
from tulip.data.haver import HaverClient as hc
from tulip.plots import plot_lines
from tulip.core import *
from tulip.data.gs import GSClient as gs
from tulip.analysis.country_related.analytics import summarize_gs_eco_fct
from tulip.core import merge_collections
from tulip.genai import iris
from tulip_mania.columns import columns
from tulip_mania.notebook_related import display_chart, display_two_charts# Country
ctry_2 = "EU"
ctry_3 = "EUR"
ccy = "EUR"
ctry_name = "Eurozone"
ccy_2 = "EU" # bloombergs currency
goldman_ctry = "EAagg"
bloomberg_ctry = "EZ"
haver_num = "025"gs_eco_fct = gs.get_eco_forecast(geographyId=goldman_ctry)
gs_summary = summarize_gs_eco_fct(gs_eco_fct)
gs_summary = gs_summary[~gs_summary.index.str.contains("ngdp")].to_frame().T
gs_summary.style.set_caption(f"Goldman {ctry_name} Economic Forecasts").format(
precision=2
)Current Activity Indicator (Goldman)¶
cai_series_soft_vs_hard = gs.get_CAI_series(
geographyId=goldman_ctry,
metricName=[
"CAI_HEADLINE",
"CAI_CONTRIBUTION_TYPE_HARD",
"CAI_CONTRIBUTION_TYPE_SOFT",
],
startDate="1980-01-01",
)
cai_last_month = cai_series_soft_vs_hard.index.max().to_period("M")
cai_update_time = cai_series_soft_vs_hard.updateTime.max().strftime("%Y-%m-%d")
cai_series_soft_vs_hard = gs.get_CAI_series(
geographyId=goldman_ctry,
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_name} Current Activity Indicator</b> Updated: {cai_update_time}",
years_limit=4,
source=f"Source: Goldman Sachs (Last data point: {cai_last_month})",
tick_suffix="%",
)
display_chart(cai_plot)cai_headline_individual_ctrys = gs.get_CAI_series(
geographyId=[goldman_ctry, "DE", "FR", "NL", "ES", "PL", "IT"],
metricName=[
"CAI_HEADLINE",
],
startDate="1980-01-01",
)
cai_headline_individual_ctrys = cai_headline_individual_ctrys.reset_index().pivot(
index="date", columns="geographyName", values="metricValue"
)
core_cai_plot = plot_lines(
cai_headline_individual_ctrys[["Euro Area", "France", "Germany", "Netherlands"]],
years_limit=3,
show_0=True,
title=f"<b>Core CAI</b> Updated: {pd.Timestamp.today().strftime('%Y-%m-%d')}",
tick_suffix="%",
figsize=(700, 400),
)
periphery_cai_plot = plot_lines(
cai_headline_individual_ctrys[["Euro Area", "Spain", "Italy", "Poland"]],
years_limit=3,
show_0=True,
title=f"<b>Periphery Countries CAI</b> Updated: {pd.Timestamp.today().strftime('%Y-%m-%d')}",
tick_suffix="%",
figsize=(700, 400),
)
with columns(2, gap="30px", vertical_alignment="center") as cols:
cols[0].plot(core_cai_plot)
cols[1].plot(periphery_cai_plot)nowcasts = bb.create_collection(
[
f"BENWEAGC Index",
f"BENWDEGC Index",
"BENWFRGC Index",
"BENWITGC Index",
"BENWESGC Index",
]
)
nowcasts.dashboard.table()Retail sales¶
The indexes below are Retail Trade Ex Autos, Motorcycles & Fuel Volume index. The closest series to US Retail Sales
retail_sales = {
"European Union (EU27)": "S997D4YK@EUDATA",
"Euro Area 20": "S025D4YK@EUDATA",
"France": "S132D4YK@EUDATA",
"Germany": "S134D4YK@EUDATA",
"Italy": "S136D4YK@EUDATA",
"Spain": "S184D4YK@EUDATA",
"Netherlands": "S138D4YK@EUDATA",
"Poland": "S964D4YK@EUDATA",
}
retail_sales_collection = hc.create_collection(retail_sales)
retail_sales_collection.dashboard.table()retail_sales_id_to_title = {
s.info.id.split("@")[0].lower(): s.info.title
for s in retail_sales_collection.tulips
}
retail_sales_df = retail_sales_collection.df.rename(columns=retail_sales_id_to_title)
retail_sales_plot = plot_lines(
retail_sales_df.iloc[:, :2],
title="<b>Retail Sales EU and Eurozone</b>",
tick_suffix="%",
show_0=True,
years_limit=10,
).add_hline(y=100, line_width=1)
retail_sales_chg_plot = plot_lines(
retail_sales_df.iloc[:, :2].pct_change(12, fill_method=None),
title="<b>Retail Sales EU and Eurozone YoY</b>",
tick_format="0.0%",
show_0=True,
years_limit=3,
)
with columns(2, gap="30px", vertical_alignment="center") as cols:
cols[0].plot(retail_sales_plot)
cols[1].plot(retail_sales_chg_plot)
retail_sales_core_plot = plot_lines(
retail_sales_df.loc[
:,
["European Union (EU27)", "Euro Area 20", "France", "Netherlands"],
],
title="<b></b>",
tick_suffix="%",
show_0=True,
years_limit=10,
default_y_range=[60, 120],
logo=False,
).add_hline(y=100, line_width=1)
retail_sales_periphery_plot = plot_lines(
retail_sales_df.loc[
:,
[
"European Union (EU27)",
"Euro Area 20",
"Italy",
"Spain",
"Poland",
],
],
title="<b></b>",
tick_suffix="%",
show_0=True,
years_limit=10,
default_y_range=[60, 120],
logo=False,
).add_hline(y=100, line_width=1)
display_two_charts(retail_sales_core_plot, retail_sales_periphery_plot)Unemployment Rate¶
ue_rate = {
"UE European Union (EU27)": "S997R@EUDATA",
"UE Euro Area 20": "S025R@EUDATA",
"UE France": "S132R@EUDATA",
"UE Germany": "S134R@EUDATA",
"UE Italy": "S136R@EUDATA",
"UE Spain": "S184R@EUDATA",
"UE Netherlands": "S138R@EUDATA",
"UE Poland": "S964R@EUDATA",
}
ue_rate_collection = hc.create_collection(ue_rate)
ue_rate_collection.good_is = -1
ue_rate_collection.dashboard.table()
cpi_id_to_title = {
s.info.id.split("@")[0].lower(): s.info.title for s in ue_rate_collection.tulips
}
ue_rate_df = ue_rate_collection.df.rename(columns=cpi_id_to_title)
ue_core_plot = plot_lines(
ue_rate_df.loc[
:,
["UE European Union (EU27)", "UE Euro Area 20", "UE France", "UE Netherlands"],
],
title="<b></b>",
tick_suffix="%",
show_0=True,
years_limit=10,
default_y_range=[0, 17],
).add_hline(y=100, line_width=1)
ue_periphery_plot = plot_lines(
ue_rate_df.loc[
:,
[
"UE European Union (EU27)",
"UE Euro Area 20",
"UE Italy",
"UE Spain",
"UE Poland",
],
],
title="<b></b>",
tick_suffix="%",
show_0=True,
years_limit=10,
default_y_range=[0, 17],
)
display_two_charts(ue_core_plot, ue_periphery_plot)
PMIs¶
pmi = {
"MPMIEZCA Index": "Eurozone Composite PMI",
"MPMIEZMA Index": "Eurozone Manufacturing PMI",
"MPMIDECA Index": "German Composite PMI",
"MPMIDEMA Index": "German Manufacturing PMI",
"MPMIFRCA Index": "France Composite PMI",
"MPMIFRMA Index": "France Manufacturing PMI",
}
pmi_collection = bb.create_collection(list(pmi.keys()))
for i, k in enumerate(pmi.values()):
pmi_collection[i].info.title = k
pmi_collection.dashboard.table()
pmi_id_to_title = {s.info.id: s.info.title for s in pmi_collection.tulips}
fig = plot_lines(
pmi_collection.df.rename(columns=pmi_id_to_title), logo=False
).add_hline(y=50, line_width=1)
display_chart(fig)Industrial Production¶
indprod = {
"IP European Union (EU27)": "S997QC@EUDATA",
"IP Euro Area 20": "S025QC@EUDATA",
"IP France": "S132QC@EUDATA",
"IP Germany": "S134QC@EUDATA",
"IP Italy": "S136QC@EUDATA",
"IP Spain": "S184QC@EUDATA",
"IP Netherlands": "S138QC@EUDATA",
"IP Poland": "S964QC@EUDATA",
}
indprod_collection = hc.create_collection(indprod)
indprod_collection.dashboard.table()ip_id_to_title = {
s.info.id.split("@")[0].lower(): s.info.title for s in indprod_collection.tulips
}
indprod_df = indprod_collection.df.rename(columns=ip_id_to_title)
ip_plot = plot_lines(
indprod_df.iloc[:, :2],
title="<b>Industrial Production EU and Eurozone</b>",
tick_suffix="%",
show_0=True,
years_limit=10,
).add_hline(y=100, line_width=1)
ip_chg_plot = plot_lines(
indprod_df.iloc[:, :2].pct_change(12, fill_method=None),
title="<b>Industrial Production EU and Eurozone YoY</b>",
tick_format="0.0%",
show_0=True,
years_limit=3,
)
display_two_charts(ip_plot, ip_chg_plot)
ip_core_plot = plot_lines(
indprod_df.loc[:, ["IP France", "IP Germany", "IP Netherlands"]],
title="<b>Industrial Production Core</b>",
tick_suffix="%",
show_0=True,
years_limit=10,
).add_hline(y=100, line_width=1)
ip_periphery_plot = plot_lines(
indprod_df.loc[:, ["IP Italy", "IP Spain", "IP Poland"]],
title="<b>Industrial Production Periphery</b>",
tick_suffix="%",
show_0=True,
years_limit=10,
).add_hline(y=100, line_width=1)
display_two_charts(ip_core_plot, ip_periphery_plot)growth_conditions = merge_collections(
[retail_sales_collection, ue_rate_collection, pmi_collection, indprod_collection]
)
growth_cond_ai = iris.summarize(
growth_conditions,
custom_prompt="While summarizing please highlight potential differences between core "
"(Germany, France, Netherlands) and periphery (Italy, Spain, Poland) countries."
" Only if they are relevant. If not just say they are not relevant."
" Do not presume the core goes better than the periphery.",
)
growth_cond_ai.html()real_gdp_eu_col = hc.create_collection(
[
"F025GDPY@EUDATA",
"F134GDPY@EUDATA",
"F132GDPY@EUDATA",
"F136GDPY@EUDATA",
"F184GDPY@EUDATA",
]
)
real_gdp_df = real_gdp_eu_col.ts
real_gdp_df.columns = ["Eurozone", "Germany", "France", "Italy", "Spain"]
plot_lines(
real_gdp_df,
title="Eurozone Real GDP Growth",
show_0=True,
source="Haver",
tick_suffix="%",
years_limit=5,
)real_gdp_eu_col.dashboard.table()GDP Detail¶
growth_stats = {
"Real GDP": f"J{haver_num}TCK@EUDATA",
"Fixed Investment": f"J{haver_num}IFK@EUDATA",
"Private Consumption": f"J{haver_num}PCK@EUDATA",
"Govt Consumption": f"J{haver_num}GCK@EUDATA",
"Exports": f"J{haver_num}EXPK@EUDATA",
"Imports": f"J{haver_num}IMPK@EUDATA", # Imports has to go last, so we can flip good_is
}
growth_stats_collection = hc.create_collection(list(growth_stats.values()))
growth_stats_collection[-1].good_is = -1 # Flip what Good is
growth_stats_collection.dashboard.table()gdp_question = iris.summarize(
growth_stats_collection,
custom_prompt="Analyze what is driving Eurozone GDP growth.Remember Imports are a drag on growth and that the eurozone requires exports.",
)
gdp_question.html()growth_stats_collection.dashboard.plots(show_0=True, years_limit=10)Nominal GDP¶
# Nominal GDP Growth
nom_gdp = hc.get_series(f"J{haver_num}GDPE@EUDATA")
nom_gdp_fig = hc.get_series(f"yryr%(J{haver_num}GDPE@EUDATA)").plot(
show_0=True,
tick_suffix="%",
) # Nominal GDP Growth
display_chart(nom_gdp_fig)Prices¶
prices = {
"EA11-20 HICP As Reported": "yryr%(F023H@EUDATA)", # Eurozone
"EA11-20 HICP": "yryr%(P023H@EUDATA)",
"EA11-20 HICP Core": "yryr%(P023HOEF@EUDATA)",
"EA20 HICP ": "yryr%(H025H@EUDATA)",
"EA20 HICP Core": " yryr%(H025HOEF@EUDATA)", # Disc
"EA20 HICP Goods": "yryr%(H025HG@EUDATA)",
"EA20 HICP Services": "yryr%(H025HS@EUDATA)",
}
prices_collection = hc.create_collection(prices)
prices_collection.dashboard.table()prices_df = prices_collection.df
prices_df.columns = list(prices.keys())
fig = plot_lines(
prices_df.iloc[:, -4:],
years_limit=8,
title="<b>Key Inflation Measures</b>",
tick_suffix="%",
source="ECB/Eurostat",
)
display_chart(
fig.add_hline(2, line_width=1, annotation_text="Target")
) # , annotation="Target")prices_per_country = {
"EA20 HICP ": "yryr%(H025H@EUDATA)",
"EA20 HICP Core": " yryr%(H025HOEF@EUDATA)",
"German HICP ": "yryr%(H134H@EUDATA)",
"German HICP Core": " yryr%(H134HOEF@EUDATA)",
"France HICP ": "yryr%(H132H@EUDATA)",
"France HICP Core": " yryr%(H132HOEF@EUDATA)",
"Italy HICP ": "yryr%(H136H@EUDATA)",
"Italy HICP Core": " yryr%(H136HOEF@EUDATA)",
"Spain HICP ": "yryr%(H184H@EUDATA)",
"Spain HICP Core": " yryr%(H184HOEF@EUDATA)",
"Netherlands HICP ": "yryr%(H138H@EUDATA)",
"Netherlands HICP Core": " yryr%(H138HOEF@EUDATA)",
"Poland HICP ": "yryr%(H964H@EUDATA)",
"Poland HICP Core": " yryr%(H964HOEF@EUDATA)",
}
prices_per_country_collection = hc.create_collection(prices_per_country)
prices_per_country_collection.dashboard.table()prices_per_country_df = prices_per_country_collection.df
prices_per_country_df.columns = list(prices_per_country.keys())overall_prices_fig = plot_lines(
prices_per_country_df.iloc[:, :2],
years_limit=3,
tick_suffix="%",
title="<b>Eurozone Inflation</b>",
logo=False,
).add_hline(2, line_width=1)
for tr in overall_prices_fig.data:
if "Core" in (tr.name or ""):
tr.update(line=dict(dash="dot"))
display_chart(overall_prices_fig)# todo: add titles to the plots
core_cpi = prices_per_country_df.loc[
:,
[
"EA20 HICP ",
"EA20 HICP Core",
"German HICP ",
"German HICP Core",
"France HICP ",
"France HICP Core",
"Netherlands HICP ",
"Netherlands HICP Core",
],
]
periphery_cpi = prices_per_country_df.loc[
:,
[
"EA20 HICP ",
"EA20 HICP Core",
"Spain HICP ",
"Spain HICP Core",
"Italy HICP ",
"Italy HICP Core",
"Poland HICP ",
"Poland HICP Core",
],
]
core_fig = plot_lines(
core_cpi,
years_limit=3,
tick_suffix="%",
title="",
logo=False,
).add_hline(2, line_width=1)
for tr in core_fig.data:
if "Core" in (tr.name or ""):
tr.update(line=dict(dash="dot"))
if "EA20" in (tr.name or ""):
tr.update(line=dict(color="blue"))
if "France" in (tr.name or ""):
tr.update(line=dict(color="red"))
if "German" in (tr.name or ""):
tr.update(line=dict(color="black"))
periphery_fig = plot_lines(
periphery_cpi,
years_limit=3,
tick_suffix="%",
title="",
logo=False,
).add_hline(2, line_width=1)
for tr in periphery_fig.data:
if "Core" in (tr.name or ""):
tr.update(line=dict(dash="dot"))
if "EA20" in (tr.name or ""):
tr.update(line=dict(color="blue"))
if "Italy" in (tr.name or ""):
tr.update(line=dict(color="green"))
if "Spain" in (tr.name or ""):
tr.update(line=dict(color="brown"))
if "Poland" in (tr.name or ""):
tr.update(line=dict(color="lightblue"))
display_two_charts(core_fig, periphery_fig)inflation_expectations = {
"Three Quarters Ahead": "V025IM23@EUDATA",
"Seven Quarters Ahead": "V025IM27@EUDATA",
"Current Year": "V025IM2C@EUDATA",
"Next year": "V025IM2N@EUDATA",
"Two years Ahead": "V025IM2Y@EUDATA",
"Long term": "V025IM2L@EUDATA",
}
inflation_expectations_collection = hc.create_collection(
list(inflation_expectations.values())
)
inflation_expectations_collection.dashboard.table()
inflation_expectations_df = inflation_expectations_collection.df
inflation_expectations_df.columns = inflation_expectations.keys()
display(HTML("<b>ECB Survey of Professional Forecasters</b>"))
fig = plot_lines(inflation_expectations_df, tick_suffix="%", years_limit=5, logo=False)
fig.add_hline(2, line_width=1, annotation_text="Target") # ,
# Color traces from dark (short horizon) to light (long term)
palette = ["#08306B", "#08519C", "#2171B5", "#4292C6", "#6BAED6", "#C6DBEF"]
for i, trc in enumerate(fig.data):
if i < len(palette):
trc.update(line=dict(color=palette[i]))
display_chart(fig)prices_col = merge_collections(
[prices_per_country_collection, inflation_expectations_collection]
)
response = iris.summarize(
prices_col,
custom_prompt="While summarizing please highlight potential differences between core "
"(Germany, France, Netherlands) and periphery (Italy, Spain, Poland) countries."
" Only if they are relevant. If not just say they are not relevant."
" Do not presume the core goes better than the periphery.",
)
response.html()from tulip_mania.notebook_related import notebook_updated
notebook_updated()