QuantumLearner commited on
Commit
70f761a
·
verified ·
1 Parent(s): 8588add

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +74 -48
app.py CHANGED
@@ -61,21 +61,9 @@ def format_value(x):
61
  else:
62
  return f"{x:.1f}"
63
 
64
- # ---- MAIN APP START ----
65
- def main():
66
- st.title("Analyst Forecasts & Estimates")
67
- st.write("This tool fetches historical financial data and analyst forecasts. "
68
- "It helps you see past trends and future estimates over your selected period.")
69
-
70
- if not run_button:
71
- st.info("Set your inputs in the sidebar, then click **Run Analysis**.")
72
- return
73
-
74
- if not ticker.strip():
75
- st.error("Please enter a valid ticker.")
76
- return
77
-
78
- # ---- FETCH AND PREPARE DATA ----
79
  hist_url = (
80
  f"https://financialmodelingprep.com/api/v3/income-statement/{ticker}"
81
  f"?period={period_api}&limit={period_count}&apikey={API_KEY}"
@@ -84,33 +72,74 @@ def main():
84
  f"https://financialmodelingprep.com/api/v3/analyst-estimates/{ticker}"
85
  f"?period={period_api}&apikey={API_KEY}"
86
  )
87
- try:
88
- hist_data = requests.get(hist_url, timeout=10).json()
89
- forecast_data = requests.get(forecast_url, timeout=10).json()
90
- except Exception:
91
- st.error("Could not retrieve data at this time.")
92
- return
 
 
 
93
 
94
- historical_df = pd.DataFrame(hist_data)
95
- forecast_df = pd.DataFrame(forecast_data)
 
 
 
 
96
 
97
- if historical_df.empty and forecast_df.empty:
98
- st.warning("No data found for the specified ticker.")
99
- return
 
 
 
 
 
 
 
 
 
100
 
101
- if not historical_df.empty and "date" in historical_df.columns:
102
- historical_df["date"] = pd.to_datetime(historical_df["date"])
103
- historical_df.sort_values("date", inplace=True)
104
- if not forecast_df.empty and "date" in forecast_df.columns:
105
- forecast_df["date"] = pd.to_datetime(forecast_df["date"])
106
- forecast_df.sort_values("date", inplace=True)
 
107
 
108
- # Filter data based on cutoff_date
109
- if "date" in historical_df.columns:
110
- historical_df = historical_df[historical_df["date"] >= cutoff_date]
111
- if "date" in forecast_df.columns:
112
- forecast_df = forecast_df[forecast_df["date"] >= cutoff_date]
113
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  metrics = {
115
  "Revenue": {
116
  "historical": "revenue",
@@ -166,7 +195,7 @@ def main():
166
  def create_plot(metric_name, hist_col, forecast_cols):
167
  fig = go.Figure()
168
 
169
- # Plot historical data as bars
170
  if hist_col in historical_df.columns and not historical_df.empty:
171
  bar_text = [format_value(val) for val in historical_df[hist_col]]
172
  fig.add_trace(go.Bar(
@@ -177,7 +206,7 @@ def main():
177
  name="Historical"
178
  ))
179
 
180
- # Plot forecast data as lines
181
  if not forecast_df.empty:
182
  for label, col in forecast_cols.items():
183
  if col in forecast_df.columns:
@@ -188,18 +217,15 @@ def main():
188
  name=f"Forecast {label}"
189
  ))
190
 
191
- # Determine which analyst count field to display
192
- if metric_name == "EPS":
193
- analyst_field = "numberAnalystsEstimatedEps"
194
- else:
195
- analyst_field = "numberAnalystEstimatedRevenue"
196
 
197
  if analyst_field in forecast_df.columns and not forecast_df.empty:
198
  analysts_count = int(round(forecast_df[analyst_field].mean()))
199
  else:
200
  analysts_count = "N/A"
201
 
202
- title_text = f"{ticker} - {metric_name} | Analysts: {analysts_count}"
203
 
204
  fig.update_layout(
205
  title=title_text,
@@ -223,7 +249,6 @@ def main():
223
  legend=dict(),
224
  margin=dict(l=40, r=40, t=80, b=80)
225
  )
226
-
227
  return fig
228
 
229
  # ---- DISPLAY RESULTS BY METRIC ----
@@ -231,12 +256,13 @@ def main():
231
  st.subheader(metric)
232
  st.write(
233
  f"This chart shows {metric} over the selected time periods. "
234
- f"Bars represent historical data and lines represent forecast ranges. "
235
  "Hover over markers for details."
236
  )
237
  fig = create_plot(metric, mapping["historical"], mapping["forecast"])
238
  st.plotly_chart(fig, use_container_width=True)
239
 
 
240
  with st.expander(f"View {metric} Data", expanded=False):
241
  relevant_cols = []
242
  hc = mapping["historical"]
@@ -270,10 +296,10 @@ def main():
270
  else:
271
  st.dataframe(merged_df.reset_index(drop=True))
272
 
273
- # ---- RUN ----
274
  if __name__ == "__main__":
275
  main()
276
 
 
277
  st.markdown(
278
  """
279
  <style>
 
61
  else:
62
  return f"{x:.1f}"
63
 
64
+ # ---- CACHED DATA FETCH FUNCTION ----
65
+ @st.cache_data(show_spinner=False)
66
+ def fetch_data(ticker, period_api, period_count, API_KEY):
 
 
 
 
 
 
 
 
 
 
 
 
67
  hist_url = (
68
  f"https://financialmodelingprep.com/api/v3/income-statement/{ticker}"
69
  f"?period={period_api}&limit={period_count}&apikey={API_KEY}"
 
72
  f"https://financialmodelingprep.com/api/v3/analyst-estimates/{ticker}"
73
  f"?period={period_api}&apikey={API_KEY}"
74
  )
75
+ hist_data = requests.get(hist_url, timeout=10).json()
76
+ forecast_data = requests.get(forecast_url, timeout=10).json()
77
+ return hist_data, forecast_data
78
+
79
+ # ---- MAIN APP START ----
80
+ def main():
81
+ st.title("Analyst Forecasts & Estimates")
82
+ st.write("This tool fetches historical financial data and analyst forecasts. "
83
+ "It helps you see past trends and future estimates over your selected period.")
84
 
85
+ # Use session_state to hold results across pages
86
+ if run_button:
87
+ # Run analysis and store results in session state.
88
+ if not ticker.strip():
89
+ st.error("Please enter a valid ticker.")
90
+ return
91
 
92
+ try:
93
+ hist_data, forecast_data = fetch_data(ticker, period_api, period_count, API_KEY)
94
+ except Exception:
95
+ st.error("Could not retrieve data at this time.")
96
+ return
97
+
98
+ historical_df = pd.DataFrame(hist_data)
99
+ forecast_df = pd.DataFrame(forecast_data)
100
+
101
+ if historical_df.empty and forecast_df.empty:
102
+ st.warning("No data found for the specified ticker.")
103
+ return
104
 
105
+ # Parse and sort dates if present.
106
+ if not historical_df.empty and "date" in historical_df.columns:
107
+ historical_df["date"] = pd.to_datetime(historical_df["date"])
108
+ historical_df.sort_values("date", inplace=True)
109
+ if not forecast_df.empty and "date" in forecast_df.columns:
110
+ forecast_df["date"] = pd.to_datetime(forecast_df["date"])
111
+ forecast_df.sort_values("date", inplace=True)
112
 
113
+ # Filter data based on cutoff_date.
114
+ if "date" in historical_df.columns:
115
+ historical_df = historical_df[historical_df["date"] >= cutoff_date]
116
+ if "date" in forecast_df.columns:
117
+ forecast_df = forecast_df[forecast_df["date"] >= cutoff_date]
118
 
119
+ # Save the processed data along with metadata in session state.
120
+ st.session_state.analysis_results = {
121
+ "ticker": ticker,
122
+ "historical_df": historical_df,
123
+ "forecast_df": forecast_df,
124
+ "xaxis_title": xaxis_title,
125
+ "tickformat": tickformat,
126
+ "dtick": dtick,
127
+ "data_period": data_period,
128
+ }
129
+ elif "analysis_results" not in st.session_state:
130
+ st.info("Set your inputs in the sidebar, then click **Run Analysis**.")
131
+ return
132
+
133
+ # Retrieve stored results if available.
134
+ res = st.session_state.analysis_results
135
+ ticker_stored = res["ticker"]
136
+ historical_df = res["historical_df"]
137
+ forecast_df = res["forecast_df"]
138
+ xaxis_title = res["xaxis_title"]
139
+ tickformat = res["tickformat"]
140
+ dtick = res["dtick"]
141
+
142
+ # --- Define Metrics Mapping ---
143
  metrics = {
144
  "Revenue": {
145
  "historical": "revenue",
 
195
  def create_plot(metric_name, hist_col, forecast_cols):
196
  fig = go.Figure()
197
 
198
+ # Plot historical data as bars.
199
  if hist_col in historical_df.columns and not historical_df.empty:
200
  bar_text = [format_value(val) for val in historical_df[hist_col]]
201
  fig.add_trace(go.Bar(
 
206
  name="Historical"
207
  ))
208
 
209
+ # Plot forecast data as lines.
210
  if not forecast_df.empty:
211
  for label, col in forecast_cols.items():
212
  if col in forecast_df.columns:
 
217
  name=f"Forecast {label}"
218
  ))
219
 
220
+ # Pick the appropriate analyst count field.
221
+ analyst_field = "numberAnalystsEstimatedEps" if metric_name == "EPS" else "numberAnalystEstimatedRevenue"
 
 
 
222
 
223
  if analyst_field in forecast_df.columns and not forecast_df.empty:
224
  analysts_count = int(round(forecast_df[analyst_field].mean()))
225
  else:
226
  analysts_count = "N/A"
227
 
228
+ title_text = f"{ticker_stored} - {metric_name} | Analysts: {analysts_count}"
229
 
230
  fig.update_layout(
231
  title=title_text,
 
249
  legend=dict(),
250
  margin=dict(l=40, r=40, t=80, b=80)
251
  )
 
252
  return fig
253
 
254
  # ---- DISPLAY RESULTS BY METRIC ----
 
256
  st.subheader(metric)
257
  st.write(
258
  f"This chart shows {metric} over the selected time periods. "
259
+ "Bars represent historical data and lines represent forecast ranges. "
260
  "Hover over markers for details."
261
  )
262
  fig = create_plot(metric, mapping["historical"], mapping["forecast"])
263
  st.plotly_chart(fig, use_container_width=True)
264
 
265
+ # Data display expander.
266
  with st.expander(f"View {metric} Data", expanded=False):
267
  relevant_cols = []
268
  hc = mapping["historical"]
 
296
  else:
297
  st.dataframe(merged_df.reset_index(drop=True))
298
 
 
299
  if __name__ == "__main__":
300
  main()
301
 
302
+ # ---- HIDE STREAMLIT DEFAULT STYLE ----
303
  st.markdown(
304
  """
305
  <style>