Benjamin Consolvo commited on
Commit
91fc69d
·
1 Parent(s): 1c9aec6

news sentiment combine

Browse files
Files changed (1) hide show
  1. app.py +71 -23
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 (moved up) ---
361
  sentiment_result = None
362
  article_headlines = []
363
  if st.button("Check Sentiment"):
364
  if symbol:
365
- try:
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 for trading and News API for sentiment analysis. Come and trade my money! Well, it's a paper account, so it's not real money. But still, have fun!")
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")