Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -2,29 +2,27 @@ import os
|
|
| 2 |
import yfinance as yf
|
| 3 |
import pandas as pd
|
| 4 |
import numpy as np
|
|
|
|
| 5 |
import plotly.graph_objects as go
|
| 6 |
import streamlit as st
|
| 7 |
-
import requests
|
| 8 |
from datetime import timedelta
|
| 9 |
from scipy.stats import norm
|
| 10 |
|
|
|
|
|
|
|
|
|
|
| 11 |
# Define functions
|
| 12 |
def fetch_earnings_data(ticker, limit=99):
|
| 13 |
"""
|
| 14 |
-
Fetch earnings data
|
| 15 |
"""
|
| 16 |
try:
|
| 17 |
-
|
| 18 |
-
api_key = os.getenv("FMP_API_KEY")
|
| 19 |
-
if not api_key:
|
| 20 |
-
raise ValueError("FMP API key is not set in the environment variables.")
|
| 21 |
-
|
| 22 |
-
url = f"https://financialmodelingprep.com/api/v3/earnings-surprises/{ticker}?apikey={api_key}"
|
| 23 |
response = requests.get(url)
|
| 24 |
response.raise_for_status()
|
| 25 |
data = response.json()
|
| 26 |
-
|
| 27 |
-
# Parse
|
| 28 |
earnings_data = pd.DataFrame(data)
|
| 29 |
earnings_data['date'] = pd.to_datetime(earnings_data['date'])
|
| 30 |
earnings_data.set_index('date', inplace=True)
|
|
@@ -40,15 +38,14 @@ def fetch_earnings_data(ticker, limit=99):
|
|
| 40 |
(earnings_data['Actual EPS'] - earnings_data['EPS Estimate'])
|
| 41 |
/ earnings_data['EPS Estimate']
|
| 42 |
) * 100
|
| 43 |
-
|
| 44 |
return earnings_data.head(limit)
|
| 45 |
except Exception as e:
|
| 46 |
st.warning(f"There was an issue fetching earnings data: {e}")
|
| 47 |
-
return pd.DataFrame()
|
| 48 |
|
| 49 |
def fetch_stock_data(ticker, start_date, end_date, buffer_days):
|
| 50 |
"""
|
| 51 |
-
Fetch historical stock data
|
| 52 |
"""
|
| 53 |
try:
|
| 54 |
start_date = start_date - pd.Timedelta(days=buffer_days)
|
|
@@ -57,80 +54,86 @@ def fetch_stock_data(ticker, start_date, end_date, buffer_days):
|
|
| 57 |
stock_data.index = stock_data.index.tz_localize(None)
|
| 58 |
return stock_data
|
| 59 |
except Exception as e:
|
| 60 |
-
st.warning("There was an issue fetching stock data
|
| 61 |
return pd.DataFrame()
|
| 62 |
|
| 63 |
def calculate_metrics(stock_data):
|
| 64 |
"""
|
| 65 |
-
|
| 66 |
"""
|
| 67 |
if not stock_data.empty:
|
| 68 |
stock_data['Returns'] = stock_data['Close'].pct_change()
|
| 69 |
stock_data['20D Volatility'] = stock_data['Returns'].rolling(window=20).std()
|
| 70 |
return stock_data
|
| 71 |
|
| 72 |
-
|
| 73 |
-
# They include plot_stock_price_with_earnings, ensure_window_size, plot_normalized_price_movements,
|
| 74 |
-
# plot_volatility_around_earnings, plot_volume_around_earnings, compute_price_effect, plot_price_effects,
|
| 75 |
-
# plot_surprise_vs_price_effect, monte_carlo_simulation, etc.
|
| 76 |
-
|
| 77 |
-
# Streamlit app
|
| 78 |
-
st.set_page_config(layout="wide")
|
| 79 |
-
st.title("Earnings Announcements Analysis")
|
| 80 |
-
st.write(
|
| 81 |
"""
|
| 82 |
-
|
| 83 |
-
on a company's stock price. By providing a ticker symbol and configuring the analysis parameters in the sidebar,
|
| 84 |
-
you can explore various aspects of stock price behavior around earnings dates and the likelihood of future movements.
|
| 85 |
"""
|
| 86 |
-
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 87 |
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
2. Enter the ticker symbol for the stock you want to analyze.
|
| 95 |
-
3. Adjust the pre and post-announcement windows to define the period around earnings dates.
|
| 96 |
-
4. Set the threshold percentage for price movement analysis.
|
| 97 |
-
5. Configure buffer days for fetching stock data.
|
| 98 |
-
6. Enter the implied volatility and days until earnings for Monte Carlo simulation.
|
| 99 |
-
7. Click the "Run Analysis" button to start the analysis.
|
| 100 |
-
""")
|
| 101 |
|
| 102 |
-
#
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
pre_announcement_window = st.number_input("Pre-announcement Window (days)", value=5, min_value=1, help="Days before the earnings announcement.")
|
| 106 |
-
post_announcement_window = st.number_input("Post-announcement Window (days)", value=10, min_value=1, help="Days after the earnings announcement.")
|
| 107 |
|
| 108 |
-
#
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
num_simulations = st.number_input("Number of Simulations for Monte Carlo", value=10000, min_value=100, help="Number of simulations for Monte Carlo analysis.")
|
| 115 |
|
| 116 |
-
# Run Analysis
|
| 117 |
if st.sidebar.button("Run Analysis"):
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
|
|
|
|
|
|
| 123 |
else:
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
if stock_data.empty:
|
| 130 |
-
st.error("Failed to fetch stock data.
|
| 131 |
else:
|
|
|
|
| 132 |
stock_data = calculate_metrics(stock_data)
|
| 133 |
-
|
| 134 |
-
#
|
| 135 |
-
|
| 136 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
import yfinance as yf
|
| 3 |
import pandas as pd
|
| 4 |
import numpy as np
|
| 5 |
+
import requests
|
| 6 |
import plotly.graph_objects as go
|
| 7 |
import streamlit as st
|
|
|
|
| 8 |
from datetime import timedelta
|
| 9 |
from scipy.stats import norm
|
| 10 |
|
| 11 |
+
# Load API key from environment variables
|
| 12 |
+
FMP_API_KEY = os.getenv("FMP_API_KEY")
|
| 13 |
+
|
| 14 |
# Define functions
|
| 15 |
def fetch_earnings_data(ticker, limit=99):
|
| 16 |
"""
|
| 17 |
+
Fetch earnings data from the Financial Modeling Prep API.
|
| 18 |
"""
|
| 19 |
try:
|
| 20 |
+
url = f"https://financialmodelingprep.com/api/v3/earnings-surprises/{ticker}?apikey={FMP_API_KEY}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
response = requests.get(url)
|
| 22 |
response.raise_for_status()
|
| 23 |
data = response.json()
|
| 24 |
+
|
| 25 |
+
# Parse the API response into a DataFrame
|
| 26 |
earnings_data = pd.DataFrame(data)
|
| 27 |
earnings_data['date'] = pd.to_datetime(earnings_data['date'])
|
| 28 |
earnings_data.set_index('date', inplace=True)
|
|
|
|
| 38 |
(earnings_data['Actual EPS'] - earnings_data['EPS Estimate'])
|
| 39 |
/ earnings_data['EPS Estimate']
|
| 40 |
) * 100
|
|
|
|
| 41 |
return earnings_data.head(limit)
|
| 42 |
except Exception as e:
|
| 43 |
st.warning(f"There was an issue fetching earnings data: {e}")
|
| 44 |
+
return pd.DataFrame() # Return an empty DataFrame on failure
|
| 45 |
|
| 46 |
def fetch_stock_data(ticker, start_date, end_date, buffer_days):
|
| 47 |
"""
|
| 48 |
+
Fetch historical stock data using yfinance.
|
| 49 |
"""
|
| 50 |
try:
|
| 51 |
start_date = start_date - pd.Timedelta(days=buffer_days)
|
|
|
|
| 54 |
stock_data.index = stock_data.index.tz_localize(None)
|
| 55 |
return stock_data
|
| 56 |
except Exception as e:
|
| 57 |
+
st.warning(f"There was an issue fetching stock data: {e}")
|
| 58 |
return pd.DataFrame()
|
| 59 |
|
| 60 |
def calculate_metrics(stock_data):
|
| 61 |
"""
|
| 62 |
+
Add metrics like daily returns and rolling volatility to the stock data.
|
| 63 |
"""
|
| 64 |
if not stock_data.empty:
|
| 65 |
stock_data['Returns'] = stock_data['Close'].pct_change()
|
| 66 |
stock_data['20D Volatility'] = stock_data['Returns'].rolling(window=20).std()
|
| 67 |
return stock_data
|
| 68 |
|
| 69 |
+
def plot_stock_price_with_earnings(stock_data, earnings_dates, ticker):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 70 |
"""
|
| 71 |
+
Plot stock prices with earnings surprises.
|
|
|
|
|
|
|
| 72 |
"""
|
| 73 |
+
fig = go.Figure()
|
| 74 |
+
fig.add_trace(go.Scatter(x=stock_data.index, y=stock_data['Close'], mode='lines', name='Stock Price'))
|
| 75 |
+
|
| 76 |
+
for index, row in earnings_dates.iterrows():
|
| 77 |
+
date = index
|
| 78 |
+
if date not in stock_data.index:
|
| 79 |
+
date = stock_data.index[stock_data.index.get_indexer([date], method='nearest')[0]]
|
| 80 |
+
surprise = row['Surprise(%)']
|
| 81 |
+
color = 'green' if surprise > 0 else 'red'
|
| 82 |
+
marker = '^' if surprise > 0 else 'v'
|
| 83 |
+
fig.add_trace(go.Scatter(
|
| 84 |
+
x=[date], y=[stock_data.loc[date, 'Close']],
|
| 85 |
+
mode='markers',
|
| 86 |
+
marker=dict(symbol='triangle-up' if marker == '^' else 'triangle-down', size=12, color=color),
|
| 87 |
+
name=f"{'Positive' if surprise > 0 else 'Negative'} EPS Surprise"
|
| 88 |
+
))
|
| 89 |
|
| 90 |
+
fig.update_layout(
|
| 91 |
+
title=f'{ticker} Stock Price with Earnings Surprises',
|
| 92 |
+
xaxis_title='Date', yaxis_title='Price',
|
| 93 |
+
template='plotly_white'
|
| 94 |
+
)
|
| 95 |
+
return fig
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 96 |
|
| 97 |
+
# Streamlit app setup
|
| 98 |
+
st.set_page_config(layout="wide")
|
| 99 |
+
st.title("Earnings Analysis with Financial Modeling Prep API")
|
|
|
|
|
|
|
| 100 |
|
| 101 |
+
# Sidebar inputs
|
| 102 |
+
st.sidebar.title("Input Parameters")
|
| 103 |
+
ticker = st.sidebar.text_input("Enter Ticker Symbol", "AAPL", help="Enter the stock ticker symbol.")
|
| 104 |
+
pre_announcement_window = st.sidebar.number_input("Pre-announcement Window (days)", value=5, min_value=1)
|
| 105 |
+
post_announcement_window = st.sidebar.number_input("Post-announcement Window (days)", value=5, min_value=1)
|
| 106 |
+
buffer_days = st.sidebar.number_input("Buffer Days", value=10, min_value=1)
|
|
|
|
| 107 |
|
|
|
|
| 108 |
if st.sidebar.button("Run Analysis"):
|
| 109 |
+
if not FMP_API_KEY:
|
| 110 |
+
st.error("Please set your FMP_API_KEY in the environment variables.")
|
| 111 |
+
else:
|
| 112 |
+
# Fetch earnings and stock data
|
| 113 |
+
earnings_data = fetch_earnings_data(ticker)
|
| 114 |
+
if earnings_data.empty:
|
| 115 |
+
st.error("Failed to fetch earnings data. Please check the ticker or API key.")
|
| 116 |
else:
|
| 117 |
+
st.subheader(f"Earnings Data for {ticker}")
|
| 118 |
+
st.dataframe(earnings_data)
|
| 119 |
+
|
| 120 |
+
min_date, max_date = earnings_data.index.min(), earnings_data.index.max()
|
| 121 |
+
stock_data = fetch_stock_data(ticker, min_date, max_date, buffer_days)
|
| 122 |
if stock_data.empty:
|
| 123 |
+
st.error("Failed to fetch stock data.")
|
| 124 |
else:
|
| 125 |
+
# Calculate additional metrics
|
| 126 |
stock_data = calculate_metrics(stock_data)
|
| 127 |
+
|
| 128 |
+
# Plot stock price with earnings
|
| 129 |
+
st.subheader(f"{ticker} Stock Price with Earnings Surprises")
|
| 130 |
+
st.plotly_chart(plot_stock_price_with_earnings(stock_data, earnings_data, ticker), use_container_width=True)
|
| 131 |
+
|
| 132 |
+
# Hide Streamlit UI elements
|
| 133 |
+
hide_streamlit_style = """
|
| 134 |
+
<style>
|
| 135 |
+
#MainMenu {visibility: hidden;}
|
| 136 |
+
footer {visibility: hidden;}
|
| 137 |
+
</style>
|
| 138 |
+
"""
|
| 139 |
+
st.markdown(hide_streamlit_style, unsafe_allow_html=True)
|