Spaces:
Running
Running
Benjamin Consolvo
commited on
Commit
·
91fc69d
1
Parent(s):
1c9aec6
news sentiment combine
Browse files
app.py
CHANGED
@@ -303,6 +303,51 @@ class TradingApp:
|
|
303 |
self.data = self.analyzer.get_historical_data(self.analyzer.symbols)
|
304 |
self.auto_trade_log = [] # Store automatic trade actions
|
305 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
306 |
def display_charts(self):
|
307 |
# Dynamically adjust columns based on number of stocks and available width
|
308 |
symbols = list(self.data.keys())
|
@@ -357,32 +402,12 @@ class TradingApp:
|
|
357 |
st.header("Manual Trade")
|
358 |
symbol = st.text_input('Enter stock symbol')
|
359 |
|
360 |
-
# --- Sentiment Check Feature (
|
361 |
sentiment_result = None
|
362 |
article_headlines = []
|
363 |
if st.button("Check Sentiment"):
|
364 |
if symbol:
|
365 |
-
|
366 |
-
# Use NewsSentiment to get sentiment
|
367 |
-
sentiment_dict = self.sentiment.get_news_sentiment([symbol])
|
368 |
-
sentiment_result = sentiment_dict.get(symbol)
|
369 |
-
# Try NewsAPI headlines first, fallback to yfinance if fails
|
370 |
-
try:
|
371 |
-
articles = self.sentiment.newsapi.get_everything(q=symbol, language='en', sort_by='publishedAt', page=1)
|
372 |
-
article_headlines = [a['title'] for a in articles.get('articles', [])[:5]]
|
373 |
-
if not article_headlines:
|
374 |
-
raise Exception("No NewsAPI headlines")
|
375 |
-
except Exception:
|
376 |
-
# Fallback to yfinance headlines
|
377 |
-
try:
|
378 |
-
ticker = yf.Ticker(symbol)
|
379 |
-
news_items = ticker.news if hasattr(ticker, "news") else []
|
380 |
-
article_headlines = [item.get('title') for item in news_items[:5] if item.get('title')]
|
381 |
-
except Exception:
|
382 |
-
article_headlines = []
|
383 |
-
except Exception as e:
|
384 |
-
sentiment_result = None
|
385 |
-
article_headlines = []
|
386 |
else:
|
387 |
sentiment_result = None
|
388 |
article_headlines = []
|
@@ -458,6 +483,26 @@ class TradingApp:
|
|
458 |
else:
|
459 |
st.error("Please enter a valid stock symbol and trade details.")
|
460 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
461 |
def auto_trade_based_on_sentiment(self, sentiment):
|
462 |
"""Execute trades based on sentiment analysis and return actions taken."""
|
463 |
actions = self._execute_sentiment_trades(sentiment)
|
@@ -470,6 +515,9 @@ class TradingApp:
|
|
470 |
actions = []
|
471 |
symbol_to_name = self.analyzer.symbol_to_name
|
472 |
for symbol, sentiment_value in sentiment.items():
|
|
|
|
|
|
|
473 |
action = None
|
474 |
is_market_open = self.alpaca.get_market_status()
|
475 |
if sentiment_value == 'Positive':
|
@@ -556,7 +604,7 @@ def get_market_times(alpaca_api):
|
|
556 |
|
557 |
def main():
|
558 |
st.title("Ben's Stock Trading Application")
|
559 |
-
st.markdown("This is a fun stock trading application that uses Alpaca API
|
560 |
|
561 |
if not st.secrets['ALPACA_API_KEY'] or not st.secrets['NEWS_API_KEY']:
|
562 |
st.error("Please configure your ALPACA_API_KEY and NEWS_API_KEY")
|
|
|
303 |
self.data = self.analyzer.get_historical_data(self.analyzer.symbols)
|
304 |
self.auto_trade_log = [] # Store automatic trade actions
|
305 |
|
306 |
+
def get_newsapi_sentiment_and_headlines(self, symbol):
|
307 |
+
"""Get sentiment and headlines using NewsAPI for a symbol."""
|
308 |
+
sentiment_result = None
|
309 |
+
article_headlines = []
|
310 |
+
try:
|
311 |
+
sentiment_dict = self.sentiment.get_news_sentiment([symbol])
|
312 |
+
sentiment_result = sentiment_dict.get(symbol)
|
313 |
+
articles = self.sentiment.newsapi.get_everything(q=symbol, language='en', sort_by='publishedAt', page=1)
|
314 |
+
article_headlines = [a['title'] for a in articles.get('articles', [])[:5]]
|
315 |
+
except Exception as e:
|
316 |
+
logger.error(f"NewsAPI sentiment/headlines error for {symbol}: {e}")
|
317 |
+
return sentiment_result, article_headlines
|
318 |
+
|
319 |
+
def get_yfinance_sentiment_and_headlines(self, symbol):
|
320 |
+
"""Get sentiment and headlines using yfinance for a symbol."""
|
321 |
+
sentiment_result = None
|
322 |
+
article_headlines = []
|
323 |
+
try:
|
324 |
+
ticker = yf.Ticker(symbol)
|
325 |
+
news_items = ticker.news if hasattr(ticker, "news") else []
|
326 |
+
article_headlines = [item.get('title') for item in news_items[:5] if item.get('title')]
|
327 |
+
# Use VADER on yfinance headlines if available
|
328 |
+
if article_headlines:
|
329 |
+
compound_score = 0
|
330 |
+
for title in article_headlines:
|
331 |
+
score = self.sentiment.sia.polarity_scores(title)['compound']
|
332 |
+
compound_score += score
|
333 |
+
avg_score = compound_score / len(article_headlines)
|
334 |
+
if avg_score > 0.1:
|
335 |
+
sentiment_result = 'Positive'
|
336 |
+
elif avg_score < -0.1:
|
337 |
+
sentiment_result = 'Negative'
|
338 |
+
else:
|
339 |
+
sentiment_result = 'Neutral'
|
340 |
+
except Exception as e:
|
341 |
+
logger.error(f"yfinance sentiment/headlines error for {symbol}: {e}")
|
342 |
+
return sentiment_result, article_headlines
|
343 |
+
|
344 |
+
def get_combined_sentiment_and_headlines(self, symbol):
|
345 |
+
"""Try NewsAPI first, fallback to yfinance if needed."""
|
346 |
+
sentiment_result, article_headlines = self.get_newsapi_sentiment_and_headlines(symbol)
|
347 |
+
if not article_headlines:
|
348 |
+
sentiment_result, article_headlines = self.get_yfinance_sentiment_and_headlines(symbol)
|
349 |
+
return sentiment_result, article_headlines
|
350 |
+
|
351 |
def display_charts(self):
|
352 |
# Dynamically adjust columns based on number of stocks and available width
|
353 |
symbols = list(self.data.keys())
|
|
|
402 |
st.header("Manual Trade")
|
403 |
symbol = st.text_input('Enter stock symbol')
|
404 |
|
405 |
+
# --- Sentiment Check Feature (refactored) ---
|
406 |
sentiment_result = None
|
407 |
article_headlines = []
|
408 |
if st.button("Check Sentiment"):
|
409 |
if symbol:
|
410 |
+
sentiment_result, article_headlines = self.get_combined_sentiment_and_headlines(symbol)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
411 |
else:
|
412 |
sentiment_result = None
|
413 |
article_headlines = []
|
|
|
483 |
else:
|
484 |
st.error("Please enter a valid stock symbol and trade details.")
|
485 |
|
486 |
+
# Display portfolio information in the sidebar (restored)
|
487 |
+
st.header("Alpaca Cash Portfolio")
|
488 |
+
|
489 |
+
def refresh_portfolio():
|
490 |
+
account = self.alpaca.alpaca.get_account()
|
491 |
+
portfolio_data = {
|
492 |
+
"Metric": ["Cash Balance", "Buying Power", "Equity", "Portfolio Value"],
|
493 |
+
"Value": [
|
494 |
+
f"${int(float(account.cash)):,.0f}",
|
495 |
+
f"${int(float(account.buying_power)):,.0f}",
|
496 |
+
f"${int(float(account.equity)):,.0f}",
|
497 |
+
f"${int(float(account.portfolio_value)):,.0f}"
|
498 |
+
]
|
499 |
+
}
|
500 |
+
df = pd.DataFrame(portfolio_data)
|
501 |
+
st.table(df.to_dict(orient="records")) # Convert DataFrame to a list of dictionaries
|
502 |
+
|
503 |
+
refresh_portfolio()
|
504 |
+
st.button("Refresh Portfolio", on_click=refresh_portfolio)
|
505 |
+
|
506 |
def auto_trade_based_on_sentiment(self, sentiment):
|
507 |
"""Execute trades based on sentiment analysis and return actions taken."""
|
508 |
actions = self._execute_sentiment_trades(sentiment)
|
|
|
515 |
actions = []
|
516 |
symbol_to_name = self.analyzer.symbol_to_name
|
517 |
for symbol, sentiment_value in sentiment.items():
|
518 |
+
# Use refactored sentiment logic for each symbol
|
519 |
+
if sentiment_value is None or sentiment_value not in ['Positive', 'Negative', 'Neutral']:
|
520 |
+
sentiment_value, _ = self.get_combined_sentiment_and_headlines(symbol)
|
521 |
action = None
|
522 |
is_market_open = self.alpaca.get_market_status()
|
523 |
if sentiment_value == 'Positive':
|
|
|
604 |
|
605 |
def main():
|
606 |
st.title("Ben's Stock Trading Application")
|
607 |
+
st.markdown("This is a fun stock trading application that uses a combination of key frameworks like Alpaca API, yfinance, and News API for stock information and trading. Come and trade my money! Well, it's a paper account, so it's not real money. But still, have fun!")
|
608 |
|
609 |
if not st.secrets['ALPACA_API_KEY'] or not st.secrets['NEWS_API_KEY']:
|
610 |
st.error("Please configure your ALPACA_API_KEY and NEWS_API_KEY")
|