Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -7,11 +7,9 @@ import os
|
|
| 7 |
|
| 8 |
API_KEY = os.getenv("FMP_API_KEY")
|
| 9 |
|
| 10 |
-
# Global constants (not exposed to the frontend)
|
| 11 |
MAX_PAGES = 5
|
| 12 |
DEFAULT_TOP_N = 10
|
| 13 |
|
| 14 |
-
# Initialize session state variables if not already set
|
| 15 |
if "historical_run" not in st.session_state:
|
| 16 |
st.session_state.historical_run = False
|
| 17 |
if "trending_run" not in st.session_state:
|
|
@@ -109,16 +107,16 @@ def plot_dual_axes(
|
|
| 109 |
|
| 110 |
def run_historical_sentiment(ticker):
|
| 111 |
st.write(
|
| 112 |
-
"This
|
| 113 |
-
"Five separate charts are generated: sentiment scores, posts, comments, likes, and impressions."
|
| 114 |
)
|
| 115 |
df = get_historical_sentiment(ticker)
|
| 116 |
if df.empty:
|
| 117 |
-
st.error("No data found for
|
| 118 |
return
|
| 119 |
common_range = [df["date"].min(), df["date"].max()]
|
| 120 |
-
|
| 121 |
st.subheader(f"{ticker} Sentiment Scores")
|
|
|
|
| 122 |
fig1 = plot_dual_axes(
|
| 123 |
df, "date", "stocktwitsSentiment", "twitterSentiment",
|
| 124 |
f"{ticker} Sentiment Scores",
|
|
@@ -128,6 +126,7 @@ def run_historical_sentiment(ticker):
|
|
| 128 |
st.plotly_chart(fig1, use_container_width=True)
|
| 129 |
|
| 130 |
st.subheader(f"{ticker} Posts")
|
|
|
|
| 131 |
fig2 = plot_dual_axes(
|
| 132 |
df, "date", "stocktwitsPosts", "twitterPosts",
|
| 133 |
f"{ticker} Posts",
|
|
@@ -137,6 +136,7 @@ def run_historical_sentiment(ticker):
|
|
| 137 |
st.plotly_chart(fig2, use_container_width=True)
|
| 138 |
|
| 139 |
st.subheader(f"{ticker} Comments")
|
|
|
|
| 140 |
fig3 = plot_dual_axes(
|
| 141 |
df, "date", "stocktwitsComments", "twitterComments",
|
| 142 |
f"{ticker} Comments",
|
|
@@ -146,6 +146,7 @@ def run_historical_sentiment(ticker):
|
|
| 146 |
st.plotly_chart(fig3, use_container_width=True)
|
| 147 |
|
| 148 |
st.subheader(f"{ticker} Likes")
|
|
|
|
| 149 |
fig4 = plot_dual_axes(
|
| 150 |
df, "date", "stocktwitsLikes", "twitterLikes",
|
| 151 |
f"{ticker} Likes",
|
|
@@ -155,6 +156,7 @@ def run_historical_sentiment(ticker):
|
|
| 155 |
st.plotly_chart(fig4, use_container_width=True)
|
| 156 |
|
| 157 |
st.subheader(f"{ticker} Impressions")
|
|
|
|
| 158 |
fig5 = plot_dual_axes(
|
| 159 |
df, "date", "stocktwitsImpressions", "twitterImpressions",
|
| 160 |
f"{ticker} Impressions",
|
|
@@ -249,13 +251,16 @@ def plot_trending(df, title, top_n):
|
|
| 249 |
|
| 250 |
def run_trending_sentiment(top_n):
|
| 251 |
st.write(
|
| 252 |
-
"This
|
| 253 |
-
"
|
| 254 |
)
|
| 255 |
st.write("## Bullish Trending Sentiment")
|
|
|
|
| 256 |
bullish_df = fetch_trending_sentiment(sentiment_type="bullish", source="stocktwits")
|
| 257 |
plot_trending(bullish_df, title="Bullish Trending Sentiment", top_n=top_n)
|
|
|
|
| 258 |
st.write("## Bearish Trending Sentiment")
|
|
|
|
| 259 |
bearish_df = fetch_trending_sentiment(sentiment_type="bearish", source="stocktwits")
|
| 260 |
plot_trending(bearish_df, title="Bearish Trending Sentiment", top_n=top_n)
|
| 261 |
|
|
@@ -345,13 +350,16 @@ def plot_change_sentiment(df, title, top_n):
|
|
| 345 |
|
| 346 |
def run_change_sentiment(top_n):
|
| 347 |
st.write(
|
| 348 |
-
"This
|
| 349 |
-
"
|
| 350 |
)
|
| 351 |
st.write("## Bullish Sentiment Change")
|
|
|
|
| 352 |
bullish_df = fetch_change_sentiment(sentiment_type="bullish", source="stocktwits")
|
| 353 |
plot_change_sentiment(bullish_df, title="Bullish Sentiment Change", top_n=top_n)
|
|
|
|
| 354 |
st.write("## Bearish Sentiment Change")
|
|
|
|
| 355 |
bearish_df = fetch_change_sentiment(sentiment_type="bearish", source="stocktwits")
|
| 356 |
plot_change_sentiment(bearish_df, title="Bearish Sentiment Change", top_n=top_n)
|
| 357 |
|
|
@@ -361,75 +369,77 @@ def run_change_sentiment(top_n):
|
|
| 361 |
|
| 362 |
def main():
|
| 363 |
st.set_page_config(page_title="Social Sentiment Analysis", layout="wide")
|
| 364 |
-
st.title("Social Sentiment
|
| 365 |
st.write(
|
| 366 |
-
"This
|
| 367 |
-
"
|
| 368 |
-
"Click the 'Run' button to update the results."
|
| 369 |
)
|
| 370 |
-
|
| 371 |
-
# Sidebar: Navigation and Options (inside an expander)
|
| 372 |
with st.sidebar.expander("Navigation and Options", expanded=True):
|
| 373 |
page = st.radio(
|
| 374 |
"Select Analysis Page",
|
| 375 |
("Historical Sentiment", "Trending Sentiment", "Sentiment Change"),
|
| 376 |
-
help="Choose the
|
| 377 |
)
|
| 378 |
-
|
| 379 |
if page == "Historical Sentiment":
|
| 380 |
ticker = st.text_input(
|
| 381 |
"Ticker Symbol",
|
| 382 |
value=st.session_state.historical_ticker,
|
| 383 |
-
help="Enter the ticker symbol for
|
| 384 |
)
|
| 385 |
if st.button("Run Historical Sentiment Analysis"):
|
| 386 |
st.session_state.historical_run = True
|
| 387 |
st.session_state.historical_ticker = ticker
|
|
|
|
| 388 |
elif page == "Trending Sentiment":
|
| 389 |
top_n = st.number_input(
|
| 390 |
"Select Top N Stocks",
|
| 391 |
-
min_value=1,
|
|
|
|
| 392 |
value=st.session_state.trending_top_n,
|
| 393 |
-
help="
|
| 394 |
)
|
| 395 |
if st.button("Run Trending Sentiment Analysis"):
|
| 396 |
st.session_state.trending_run = True
|
| 397 |
st.session_state.trending_top_n = top_n
|
|
|
|
| 398 |
elif page == "Sentiment Change":
|
| 399 |
top_n = st.number_input(
|
| 400 |
"Select Top N Stocks",
|
| 401 |
-
min_value=1,
|
|
|
|
| 402 |
value=st.session_state.change_top_n,
|
| 403 |
-
help="
|
| 404 |
)
|
| 405 |
if st.button("Run Sentiment Change Analysis"):
|
| 406 |
st.session_state.change_run = True
|
| 407 |
st.session_state.change_top_n = top_n
|
| 408 |
|
| 409 |
-
# Main body: Display results based on the selected page and if run button was clicked
|
| 410 |
if page == "Historical Sentiment":
|
| 411 |
st.header("Historical Social Sentiment")
|
| 412 |
if st.session_state.historical_run:
|
| 413 |
run_historical_sentiment(st.session_state.historical_ticker)
|
| 414 |
else:
|
| 415 |
-
st.info("
|
|
|
|
| 416 |
elif page == "Trending Sentiment":
|
| 417 |
st.header("Trending Social Sentiment")
|
| 418 |
if st.session_state.trending_run:
|
| 419 |
run_trending_sentiment(st.session_state.trending_top_n)
|
| 420 |
else:
|
| 421 |
-
st.info("
|
|
|
|
| 422 |
elif page == "Sentiment Change":
|
| 423 |
st.header("Social Sentiment Change")
|
| 424 |
if st.session_state.change_run:
|
| 425 |
run_change_sentiment(st.session_state.change_top_n)
|
| 426 |
else:
|
| 427 |
-
st.info("
|
| 428 |
|
| 429 |
if __name__ == "__main__":
|
| 430 |
main()
|
| 431 |
|
| 432 |
-
|
| 433 |
hide_streamlit_style = """
|
| 434 |
<style>
|
| 435 |
#MainMenu {visibility: hidden;}
|
|
@@ -437,4 +447,3 @@ footer {visibility: hidden;}
|
|
| 437 |
</style>
|
| 438 |
"""
|
| 439 |
st.markdown(hide_streamlit_style, unsafe_allow_html=True)
|
| 440 |
-
|
|
|
|
| 7 |
|
| 8 |
API_KEY = os.getenv("FMP_API_KEY")
|
| 9 |
|
|
|
|
| 10 |
MAX_PAGES = 5
|
| 11 |
DEFAULT_TOP_N = 10
|
| 12 |
|
|
|
|
| 13 |
if "historical_run" not in st.session_state:
|
| 14 |
st.session_state.historical_run = False
|
| 15 |
if "trending_run" not in st.session_state:
|
|
|
|
| 107 |
|
| 108 |
def run_historical_sentiment(ticker):
|
| 109 |
st.write(
|
| 110 |
+
"This section shows how Stocktwits and Twitter sentiment changed over time."
|
|
|
|
| 111 |
)
|
| 112 |
df = get_historical_sentiment(ticker)
|
| 113 |
if df.empty:
|
| 114 |
+
st.error("No data found for " + ticker)
|
| 115 |
return
|
| 116 |
common_range = [df["date"].min(), df["date"].max()]
|
| 117 |
+
|
| 118 |
st.subheader(f"{ticker} Sentiment Scores")
|
| 119 |
+
st.write("This plot compares the sentiment scores from Stocktwits and Twitter.")
|
| 120 |
fig1 = plot_dual_axes(
|
| 121 |
df, "date", "stocktwitsSentiment", "twitterSentiment",
|
| 122 |
f"{ticker} Sentiment Scores",
|
|
|
|
| 126 |
st.plotly_chart(fig1, use_container_width=True)
|
| 127 |
|
| 128 |
st.subheader(f"{ticker} Posts")
|
| 129 |
+
st.write("This plot compares how many posts appear on each platform.")
|
| 130 |
fig2 = plot_dual_axes(
|
| 131 |
df, "date", "stocktwitsPosts", "twitterPosts",
|
| 132 |
f"{ticker} Posts",
|
|
|
|
| 136 |
st.plotly_chart(fig2, use_container_width=True)
|
| 137 |
|
| 138 |
st.subheader(f"{ticker} Comments")
|
| 139 |
+
st.write("This plot compares the number of comments on Stocktwits and Twitter.")
|
| 140 |
fig3 = plot_dual_axes(
|
| 141 |
df, "date", "stocktwitsComments", "twitterComments",
|
| 142 |
f"{ticker} Comments",
|
|
|
|
| 146 |
st.plotly_chart(fig3, use_container_width=True)
|
| 147 |
|
| 148 |
st.subheader(f"{ticker} Likes")
|
| 149 |
+
st.write("This plot compares how many likes each platform received.")
|
| 150 |
fig4 = plot_dual_axes(
|
| 151 |
df, "date", "stocktwitsLikes", "twitterLikes",
|
| 152 |
f"{ticker} Likes",
|
|
|
|
| 156 |
st.plotly_chart(fig4, use_container_width=True)
|
| 157 |
|
| 158 |
st.subheader(f"{ticker} Impressions")
|
| 159 |
+
st.write("This plot compares the total impressions from Stocktwits and Twitter.")
|
| 160 |
fig5 = plot_dual_axes(
|
| 161 |
df, "date", "stocktwitsImpressions", "twitterImpressions",
|
| 162 |
f"{ticker} Impressions",
|
|
|
|
| 251 |
|
| 252 |
def run_trending_sentiment(top_n):
|
| 253 |
st.write(
|
| 254 |
+
"This section ranks stocks by bullish and bearish sentiment. "
|
| 255 |
+
"Two charts show the sentiment versus last known sentiment."
|
| 256 |
)
|
| 257 |
st.write("## Bullish Trending Sentiment")
|
| 258 |
+
st.write("The first chart shows the top bullish stocks and how sentiment changed from the last update.")
|
| 259 |
bullish_df = fetch_trending_sentiment(sentiment_type="bullish", source="stocktwits")
|
| 260 |
plot_trending(bullish_df, title="Bullish Trending Sentiment", top_n=top_n)
|
| 261 |
+
|
| 262 |
st.write("## Bearish Trending Sentiment")
|
| 263 |
+
st.write("The second chart shows the top bearish stocks and how sentiment changed from the last update.")
|
| 264 |
bearish_df = fetch_trending_sentiment(sentiment_type="bearish", source="stocktwits")
|
| 265 |
plot_trending(bearish_df, title="Bearish Trending Sentiment", top_n=top_n)
|
| 266 |
|
|
|
|
| 350 |
|
| 351 |
def run_change_sentiment(top_n):
|
| 352 |
st.write(
|
| 353 |
+
"This section shows how sentiment scores have changed. "
|
| 354 |
+
"We compare current sentiment to the change in sentiment."
|
| 355 |
)
|
| 356 |
st.write("## Bullish Sentiment Change")
|
| 357 |
+
st.write("This chart displays current bullish sentiment and how much it has changed recently.")
|
| 358 |
bullish_df = fetch_change_sentiment(sentiment_type="bullish", source="stocktwits")
|
| 359 |
plot_change_sentiment(bullish_df, title="Bullish Sentiment Change", top_n=top_n)
|
| 360 |
+
|
| 361 |
st.write("## Bearish Sentiment Change")
|
| 362 |
+
st.write("This chart displays current bearish sentiment and how much it has changed recently.")
|
| 363 |
bearish_df = fetch_change_sentiment(sentiment_type="bearish", source="stocktwits")
|
| 364 |
plot_change_sentiment(bearish_df, title="Bearish Sentiment Change", top_n=top_n)
|
| 365 |
|
|
|
|
| 369 |
|
| 370 |
def main():
|
| 371 |
st.set_page_config(page_title="Social Sentiment Analysis", layout="wide")
|
| 372 |
+
st.title("Trending Social Sentiment")
|
| 373 |
st.write(
|
| 374 |
+
"This tool offers three analyses of social sentiment. "
|
| 375 |
+
"They cover historical, trending, and changing sentiment from Stocktwits and Twitter. "
|
|
|
|
| 376 |
)
|
| 377 |
+
|
|
|
|
| 378 |
with st.sidebar.expander("Navigation and Options", expanded=True):
|
| 379 |
page = st.radio(
|
| 380 |
"Select Analysis Page",
|
| 381 |
("Historical Sentiment", "Trending Sentiment", "Sentiment Change"),
|
| 382 |
+
help="Choose the type of sentiment analysis you want."
|
| 383 |
)
|
| 384 |
+
|
| 385 |
if page == "Historical Sentiment":
|
| 386 |
ticker = st.text_input(
|
| 387 |
"Ticker Symbol",
|
| 388 |
value=st.session_state.historical_ticker,
|
| 389 |
+
help="Enter the ticker symbol for historical sentiment."
|
| 390 |
)
|
| 391 |
if st.button("Run Historical Sentiment Analysis"):
|
| 392 |
st.session_state.historical_run = True
|
| 393 |
st.session_state.historical_ticker = ticker
|
| 394 |
+
|
| 395 |
elif page == "Trending Sentiment":
|
| 396 |
top_n = st.number_input(
|
| 397 |
"Select Top N Stocks",
|
| 398 |
+
min_value=1,
|
| 399 |
+
max_value=100,
|
| 400 |
value=st.session_state.trending_top_n,
|
| 401 |
+
help="Pick how many stocks to show."
|
| 402 |
)
|
| 403 |
if st.button("Run Trending Sentiment Analysis"):
|
| 404 |
st.session_state.trending_run = True
|
| 405 |
st.session_state.trending_top_n = top_n
|
| 406 |
+
|
| 407 |
elif page == "Sentiment Change":
|
| 408 |
top_n = st.number_input(
|
| 409 |
"Select Top N Stocks",
|
| 410 |
+
min_value=1,
|
| 411 |
+
max_value=100,
|
| 412 |
value=st.session_state.change_top_n,
|
| 413 |
+
help="Pick how many stocks to show."
|
| 414 |
)
|
| 415 |
if st.button("Run Sentiment Change Analysis"):
|
| 416 |
st.session_state.change_run = True
|
| 417 |
st.session_state.change_top_n = top_n
|
| 418 |
|
|
|
|
| 419 |
if page == "Historical Sentiment":
|
| 420 |
st.header("Historical Social Sentiment")
|
| 421 |
if st.session_state.historical_run:
|
| 422 |
run_historical_sentiment(st.session_state.historical_ticker)
|
| 423 |
else:
|
| 424 |
+
st.info("Enter a ticker and run the analysis.")
|
| 425 |
+
|
| 426 |
elif page == "Trending Sentiment":
|
| 427 |
st.header("Trending Social Sentiment")
|
| 428 |
if st.session_state.trending_run:
|
| 429 |
run_trending_sentiment(st.session_state.trending_top_n)
|
| 430 |
else:
|
| 431 |
+
st.info("Select a top N and run the analysis.")
|
| 432 |
+
|
| 433 |
elif page == "Sentiment Change":
|
| 434 |
st.header("Social Sentiment Change")
|
| 435 |
if st.session_state.change_run:
|
| 436 |
run_change_sentiment(st.session_state.change_top_n)
|
| 437 |
else:
|
| 438 |
+
st.info("Select a top N and run the analysis.")
|
| 439 |
|
| 440 |
if __name__ == "__main__":
|
| 441 |
main()
|
| 442 |
|
|
|
|
| 443 |
hide_streamlit_style = """
|
| 444 |
<style>
|
| 445 |
#MainMenu {visibility: hidden;}
|
|
|
|
| 447 |
</style>
|
| 448 |
"""
|
| 449 |
st.markdown(hide_streamlit_style, unsafe_allow_html=True)
|
|
|