QuantumLearner commited on
Commit
1ebc508
·
verified ·
1 Parent(s): ea89a70

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +181 -157
app.py CHANGED
@@ -7,7 +7,6 @@ import plotly.graph_objs as go
7
  # Set up the layout
8
  st.set_page_config(layout="wide")
9
 
10
-
11
  # Custom CSS to adjust the sidebar width
12
  st.markdown(
13
  """
@@ -26,7 +25,6 @@ st.markdown(
26
  unsafe_allow_html=True,
27
  )
28
 
29
-
30
  # App title and description
31
  st.title("Key Economic Recession Indicators")
32
  st.markdown("""
@@ -94,175 +92,201 @@ crash_periods = {
94
 
95
  # Run button
96
  if st.sidebar.button('Run Analysis'):
97
- # Fetch the data from FRED
98
- sahm_recession_indicator = web.DataReader('SAHMREALTIME', 'fred', start_date, end_date)
99
- retail_sales = web.DataReader('RSXFS', 'fred', start_date, end_date)
100
- industrial_production = web.DataReader('INDPRO', 'fred', start_date, end_date)
101
- unemployment_rate = web.DataReader('UNRATE', 'fred', start_date, end_date)
102
- inflation = web.DataReader('CPIAUCSL', 'fred', start_date, end_date)
103
- nonfarm_payrolls = web.DataReader('PAYEMS', 'fred', start_date, end_date)
104
- jobless_claims = web.DataReader('ICSA', 'fred', start_date, end_date)
105
- consumer_confidence = web.DataReader('UMCSENT', 'fred', start_date, end_date)
106
- housing_starts = web.DataReader('HOUST', 'fred', start_date, end_date)
107
- treasury_rate_10y = web.DataReader('GS10', 'fred', start_date, end_date)
108
- treasury_rate_2y = web.DataReader('DGS2', 'fred', start_date, end_date)
109
- treasury_rate_1m = web.DataReader('DGS1MO', 'fred', start_date, end_date)
110
- treasury_rate_3m = web.DataReader('TB3MS', 'fred', start_date, end_date)
111
- federal_funds_rate = web.DataReader('FEDFUNDS', 'fred', start_date, end_date)
112
- recession_probabilities = web.DataReader('RECPROUSM156N', 'fred', start_date, end_date)
113
 
114
- # Rename columns for clarity
115
- recession_probabilities.columns = ['Recession_Probabilities']
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
 
117
- # Fetch the data from Yahoo Finance
118
- sp500 = yf.download('^GSPC', start=start_date, end=end_date)['Adj Close']
119
- vix = yf.download('^VIX', start=start_date, end=end_date)['Adj Close']
 
 
 
 
 
 
 
 
120
 
121
- # Calculate percentage changes for relevant indicators
122
- industrial_production_pct = industrial_production.pct_change() * 100
123
- inflation_pct = inflation.pct_change() * 100
 
 
 
 
 
 
 
124
 
125
- # Rename columns for clarity
126
- industrial_production_pct = industrial_production_pct.rename(columns={'INDPRO': 'INDPRO_PCT'})
127
- inflation_pct = inflation_pct.rename(columns={'CPIAUCSL': 'CPIAUCSL_PCT'})
 
128
 
129
- # Combine all data into a single DataFrame, aligning by date
130
- combined_data = sahm_recession_indicator.join([
131
- retail_sales, industrial_production, industrial_production_pct,
132
- unemployment_rate, inflation, inflation_pct,
133
- sp500.rename('SP500'), nonfarm_payrolls, jobless_claims,
134
- consumer_confidence, housing_starts, treasury_rate_10y, treasury_rate_2y, treasury_rate_1m, treasury_rate_3m, federal_funds_rate, vix.rename('VIX'),
135
- recession_probabilities
136
- ], how='outer')
137
 
138
- # Interpolate missing values for alignment
139
- combined_data = combined_data.interpolate(method='time')
 
 
 
 
140
 
141
- # Calculate the yield spread
142
- combined_data['Yield_Spread'] = combined_data['GS10'] - combined_data['DGS2']
 
 
143
 
144
- # Plot each selected series
145
- for key, column in indicators.items():
146
- if selected_indicators[key]:
147
- fig = go.Figure()
148
-
149
- # Add recession shading
150
- for peak, trough in crash_periods.items():
151
- fig.add_shape(
152
- type="rect",
153
- xref="x",
154
- yref="paper",
155
- x0=peak,
156
- y0=0,
157
- x1=trough,
158
- y1=1,
159
- fillcolor="gray",
160
- opacity=0.3,
161
- layer="below",
162
- line_width=0,
163
- )
164
-
165
- if isinstance(column, tuple):
166
- if column == ('INDPRO', 'INDPRO_PCT'):
167
- # Plot industrial production and its percentage change on dual y-axes
168
- fig.add_trace(go.Scatter(x=combined_data.index, y=combined_data['INDPRO'], mode='lines', name='Industrial Production'))
169
- fig.add_trace(go.Scatter(x=combined_data.index, y=combined_data['INDPRO_PCT'], mode='lines', name='Industrial Production % Change', yaxis='y2'))
170
 
171
- # Create a secondary y-axis and place the legend inside the plot area
172
- fig.update_layout(
173
- yaxis2=dict(
174
- title="Industrial Production % Change",
175
- overlaying='y',
176
- side='right'
177
- ),
178
- legend=dict(
179
- x=0.02,
180
- y=0.95,
181
- traceorder='normal',
182
- bgcolor='rgba(255, 255, 255, 0.5)',
183
- bordercolor='rgba(0, 0, 0, 0)'
184
- )
185
- )
186
- elif column == ('CPIAUCSL', 'CPIAUCSL_PCT'):
187
- # Plot inflation and its percentage change on dual y-axes
188
- fig.add_trace(go.Scatter(x=combined_data.index, y=combined_data['CPIAUCSL'], mode='lines', name='Inflation (CPI)'))
189
- fig.add_trace(go.Scatter(x=combined_data.index, y=combined_data['CPIAUCSL_PCT'], mode='lines', name='Inflation % Change', yaxis='y2'))
190
 
191
- # Create a secondary y-axis and place the legend inside the plot area
192
- fig.update_layout(
193
- yaxis2=dict(
194
- title="Inflation % Change",
195
- overlaying='y',
196
- side='right'
197
- ),
198
- legend=dict(
199
- x=0.02,
200
- y=0.95,
201
- traceorder='normal',
202
- bgcolor='rgba(255, 255, 255, 0.5)',
203
- bordercolor='rgba(0, 0, 0, 0)'
204
- )
 
 
 
 
 
205
  )
206
- elif column == ('GS10', 'DGS2', 'DGS1MO', 'TB3MS'):
207
- # Plot multiple Treasury rates in the same subplot
208
- for col in column:
209
- fig.add_trace(go.Scatter(x=combined_data.index, y=combined_data[col], mode='lines', name=col))
210
-
211
- # Place the legend inside the plot area
212
- fig.update_layout(
213
- legend=dict(
214
- x=0.02,
215
- y=0.95,
216
- traceorder='normal',
217
- bgcolor='rgba(255, 255, 255, 0.5)',
218
- bordercolor='rgba(0, 0, 0, 0)'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
219
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220
  )
221
- else:
222
- fig.add_trace(go.Scatter(x=combined_data.index, y=combined_data[column], mode='lines', name=key))
 
 
 
 
 
 
 
 
 
223
 
224
- # Add horizontal threshold line for Sahm Recession Indicator
225
- if column == 'SAHMREALTIME':
226
- fig.add_hline(y=0.5, line=dict(color="red", dash="dash"), annotation_text="Recession Threshold", annotation_position="bottom right")
227
-
228
- # Update layout with detailed date formatting
229
- fig.update_layout(
230
- title=key,
231
- xaxis_title='Date',
232
- yaxis_title=key,
233
- xaxis=dict(
234
- tickformat="%Y", # Yearly ticks
235
- tickmode="linear",
236
- dtick="M36", # Ticks every 12 months, M24 Every 2 years and 5 years is M60
237
- showspikes=True,
238
- spikemode='across',
239
- spikesnap='cursor',
240
- spikethickness=1
241
- ),
242
- hovermode="x unified",
243
- hoverlabel=dict(
244
- bgcolor="white",
245
- font_size=12,
246
- font_family="Rockwell"
247
  )
248
- )
249
- fig.update_xaxes(
250
- showgrid=True,
251
- gridwidth=1,
252
- gridcolor='LightGray',
253
- tickangle=45,
254
- tickformatstops=[
255
- dict(dtickrange=[None, "M1"], value="%b %d, %Y"), # Format as "Month Day, Year" for better granularity
256
- dict(dtickrange=["M1", None], value="%Y") # Year format for larger intervals
257
- ]
258
- )
259
-
260
- # Ensure full date is shown on hover
261
- fig.update_traces(
262
- hovertemplate='%{x|%b %d, %Y}<br>%{y}<extra></extra>'
263
- )
264
-
265
- st.plotly_chart(fig, use_container_width=True)
266
 
267
  hide_streamlit_style = """
268
  <style>
@@ -270,4 +294,4 @@ hide_streamlit_style = """
270
  footer {visibility: hidden;}
271
  </style>
272
  """
273
- st.markdown(hide_streamlit_style, unsafe_allow_html=True)
 
7
  # Set up the layout
8
  st.set_page_config(layout="wide")
9
 
 
10
  # Custom CSS to adjust the sidebar width
11
  st.markdown(
12
  """
 
25
  unsafe_allow_html=True,
26
  )
27
 
 
28
  # App title and description
29
  st.title("Key Economic Recession Indicators")
30
  st.markdown("""
 
92
 
93
  # Run button
94
  if st.sidebar.button('Run Analysis'):
95
+ # Initialize combined_data as an empty DataFrame
96
+ combined_data = pd.DataFrame()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
 
98
+ # Fetch FRED data with error handling
99
+ fred_data = {}
100
+ for key, column in indicators.items():
101
+ if selected_indicators[key]:
102
+ if isinstance(column, tuple):
103
+ for col in column:
104
+ if col not in ['INDPRO_PCT', 'CPIAUCSL_PCT']: # Skip derived columns
105
+ try:
106
+ fred_data[col] = web.DataReader(col, 'fred', start_date, end_date)
107
+ except Exception as e:
108
+ st.warning(f"Failed to fetch {col} from FRED: {e}")
109
+ fred_data[col] = pd.DataFrame()
110
+ else:
111
+ try:
112
+ fred_data[column] = web.DataReader(column, 'fred', start_date, end_date)
113
+ except Exception as e:
114
+ st.warning(f"Failed to fetch {column} from FRED: {e}")
115
+ fred_data[column] = pd.DataFrame()
116
 
117
+ # Fetch Yahoo Finance data with yfinance adjustments
118
+ if selected_indicators['Stock Market (S&P 500)']:
119
+ try:
120
+ sp500 = yf.download('^GSPC', start=start_date, end=end_date, auto_adjust=False)
121
+ if isinstance(sp500.columns, pd.MultiIndex):
122
+ sp500.columns = sp500.columns.get_level_values(0)
123
+ sp500 = sp500['Adj Close'].rename('SP500')
124
+ fred_data['SP500'] = sp500
125
+ except Exception as e:
126
+ st.warning(f"Failed to fetch S&P 500 data: {e}")
127
+ fred_data['SP500'] = pd.DataFrame()
128
 
129
+ if selected_indicators['VIX']:
130
+ try:
131
+ vix = yf.download('^VIX', start=start_date, end=end_date, auto_adjust=False)
132
+ if isinstance(vix.columns, pd.MultiIndex):
133
+ vix.columns = vix.columns.get_level_values(0)
134
+ vix = vix['Adj Close'].rename('VIX')
135
+ fred_data['VIX'] = vix
136
+ except Exception as e:
137
+ st.warning(f"Failed to fetch VIX data: {e}")
138
+ fred_data['VIX'] = pd.DataFrame()
139
 
140
+ # Rename recession probabilities for clarity
141
+ if 'RECPROUSM156N' in fred_data:
142
+ fred_data['RECPROUSM156N'].columns = ['Recession_Probabilities']
143
+ fred_data['Recession_Probabilities'] = fred_data.pop('RECPROUSM156N')
144
 
145
+ # Combine all FRED and Yahoo Finance data
146
+ if fred_data:
147
+ combined_data = pd.concat(fred_data.values(), axis=1, join='outer')
148
+ combined_data.columns = [col for col in fred_data.keys() if not col.endswith('_PCT')] # Exclude derived columns for now
 
 
 
 
149
 
150
+ if not combined_data.empty:
151
+ # Calculate percentage changes for relevant indicators
152
+ if selected_indicators['Industrial Production']:
153
+ industrial_production = combined_data.get('INDPRO', pd.Series())
154
+ if not industrial_production.empty:
155
+ combined_data['INDPRO_PCT'] = industrial_production.pct_change() * 100
156
 
157
+ if selected_indicators['Inflation (CPI)']:
158
+ inflation = combined_data.get('CPIAUCSL', pd.Series())
159
+ if not inflation.empty:
160
+ combined_data['CPIAUCSL_PCT'] = inflation.pct_change() * 100
161
 
162
+ # Interpolate missing values for alignment
163
+ combined_data = combined_data.interpolate(method='time')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
 
165
+ # Calculate the yield spread
166
+ if selected_indicators['Yield Spread (10Y - 2Y)'] and 'GS10' in combined_data and 'DGS2' in combined_data:
167
+ combined_data['Yield_Spread'] = combined_data['GS10'] - combined_data['DGS2']
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
 
169
+ # Plot each selected series
170
+ for key, column in indicators.items():
171
+ if selected_indicators[key]:
172
+ fig = go.Figure()
173
+
174
+ # Add recession shading
175
+ for peak, trough in crash_periods.items():
176
+ fig.add_shape(
177
+ type="rect",
178
+ xref="x",
179
+ yref="paper",
180
+ x0=peak,
181
+ y0=0,
182
+ x1=trough,
183
+ y1=1,
184
+ fillcolor="gray",
185
+ opacity=0.3,
186
+ layer="below",
187
+ line_width=0,
188
  )
189
+
190
+ if isinstance(column, tuple):
191
+ if column == ('INDPRO', 'INDPRO_PCT') and 'INDPRO' in combined_data:
192
+ # Plot industrial production and its percentage change on dual y-axes
193
+ fig.add_trace(go.Scatter(x=combined_data.index, y=combined_data['INDPRO'], mode='lines', name='Industrial Production'))
194
+ if 'INDPRO_PCT' in combined_data:
195
+ fig.add_trace(go.Scatter(x=combined_data.index, y=combined_data['INDPRO_PCT'], mode='lines', name='Industrial Production % Change', yaxis='y2'))
196
+ fig.update_layout(
197
+ yaxis2=dict(
198
+ title="Industrial Production % Change",
199
+ overlaying='y',
200
+ side='right'
201
+ ),
202
+ legend=dict(
203
+ x=0.02,
204
+ y=0.95,
205
+ traceorder='normal',
206
+ bgcolor='rgba(255, 255, 255, 0.5)',
207
+ bordercolor='rgba(0, 0, 0, 0)'
208
+ )
209
+ )
210
+ elif column == ('CPIAUCSL', 'CPIAUCSL_PCT') and 'CPIAUCSL' in combined_data:
211
+ # Plot inflation and its percentage change on dual y-axes
212
+ fig.add_trace(go.Scatter(x=combined_data.index, y=combined_data['CPIAUCSL'], mode='lines', name='Inflation (CPI)'))
213
+ if 'CPIAUCSL_PCT' in combined_data:
214
+ fig.add_trace(go.Scatter(x=combined_data.index, y=combined_data['CPIAUCSL_PCT'], mode='lines', name='Inflation % Change', yaxis='y2'))
215
+ fig.update_layout(
216
+ yaxis2=dict(
217
+ title="Inflation % Change",
218
+ overlaying='y',
219
+ side='right'
220
+ ),
221
+ legend=dict(
222
+ x=0.02,
223
+ y=0.95,
224
+ traceorder='normal',
225
+ bgcolor='rgba(255, 255, 255, 0.5)',
226
+ bordercolor='rgba(0, 0, 0, 0)'
227
+ )
228
+ )
229
+ elif column == ('GS10', 'DGS2', 'DGS1MO', 'TB3MS'):
230
+ # Plot multiple Treasury rates in the same subplot
231
+ for col in column:
232
+ if col in combined_data:
233
+ fig.add_trace(go.Scatter(x=combined_data.index, y=combined_data[col], mode='lines', name=col))
234
+ fig.update_layout(
235
+ legend=dict(
236
+ x=0.02,
237
+ y=0.95,
238
+ traceorder='normal',
239
+ bgcolor='rgba(255, 255, 255, 0.5)',
240
+ bordercolor='rgba(0, 0, 0, 0)'
241
+ )
242
  )
243
+ else:
244
+ if column in combined_data:
245
+ fig.add_trace(go.Scatter(x=combined_data.index, y=combined_data[column], mode='lines', name=key))
246
+ # Add horizontal threshold line for Sahm Recession Indicator
247
+ if column == 'SAHMREALTIME':
248
+ fig.add_hline(y=0.5, line=dict(color="red", dash="dash"), annotation_text="Recession Threshold", annotation_position="bottom right")
249
+
250
+ # Update layout with detailed date formatting
251
+ fig.update_layout(
252
+ title=key,
253
+ xaxis_title='Date',
254
+ yaxis_title=key,
255
+ xaxis=dict(
256
+ tickformat="%Y",
257
+ tickmode="linear",
258
+ dtick="M36",
259
+ showspikes=True,
260
+ spikemode='across',
261
+ spikesnap='cursor',
262
+ spikethickness=1
263
+ ),
264
+ hovermode="x unified",
265
+ hoverlabel=dict(
266
+ bgcolor="white",
267
+ font_size=12,
268
+ font_family="Rockwell"
269
  )
270
+ )
271
+ fig.update_xaxes(
272
+ showgrid=True,
273
+ gridwidth=1,
274
+ gridcolor='LightGray',
275
+ tickangle=45,
276
+ tickformatstops=[
277
+ dict(dtickrange=[None, "M1"], value="%b %d, %Y"),
278
+ dict(dtickrange=["M1", None], value="%Y")
279
+ ]
280
+ )
281
 
282
+ # Ensure full date is shown on hover
283
+ fig.update_traces(
284
+ hovertemplate='%{x|%b %d, %Y}<br>%{y}<extra></extra>'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
285
  )
286
+
287
+ st.plotly_chart(fig, use_container_width=True)
288
+ else:
289
+ st.error("No data was successfully fetched for the selected indicators.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
290
 
291
  hide_streamlit_style = """
292
  <style>
 
294
  footer {visibility: hidden;}
295
  </style>
296
  """
297
+ st.markdown(hide_streamlit_style, unsafe_allow_html=True)