From 08d4b8a020887f146926f5d299993c5ef2b5d279 Mon Sep 17 00:00:00 2001 From: Shrividya Hegde Date: Thu, 18 Dec 2025 15:05:28 -0500 Subject: [PATCH 1/2] chore: add pre-commit fixes --- src/app.py | 28 ++++++++++++++-------------- src/fetch_news.py | 14 +++++++++----- src/fetch_stock.py | 4 ++-- src/sentiment.py | 6 +++--- src/visualization.py | 20 ++++++++++---------- 5 files changed, 38 insertions(+), 34 deletions(-) diff --git a/src/app.py b/src/app.py index f073418..3c4283a 100644 --- a/src/app.py +++ b/src/app.py @@ -8,36 +8,36 @@ from sentiment import analyze_sentiment from visualization import plot_sentiment_summary -st.title('Real-Time Stock Sentiment Analyzer') +st.title("Real-Time Stock Sentiment Analyzer") # Data mode selection -data_mode = st.radio('Select Data Mode:', ('Real-Time', 'Sample Data')) +data_mode = st.radio("Select Data Mode:", ("Real-Time", "Sample Data")) -ticker = st.text_input('Enter Stock Ticker:', 'AAPL') -api_key = os.getenv('NEWS_API_KEY') +ticker = st.text_input("Enter Stock Ticker:", "AAPL") +api_key = os.getenv("NEWS_API_KEY") -if st.button('Fetch Data'): - st.subheader('Stock Data') -if data_mode == 'Real-Time': +if st.button("Fetch Data"): + st.subheader("Stock Data") +if data_mode == "Real-Time": data = get_stock_data(ticker) else: - data = pd.read_csv('data/sample_stock.csv') + data = pd.read_csv("data/sample_stock.csv") data.columns = data.columns.str.strip() # Remove any spaces print(data.columns) - data = pd.read_csv('data/sample_stock.csv', parse_dates=['Date'], index_col='Date') -st.line_chart(data['Close']) -st.subheader('Latest News Sentiment') + data = pd.read_csv("data/sample_stock.csv", parse_dates=["Date"], index_col="Date") +st.line_chart(data["Close"]) +st.subheader("Latest News Sentiment") sentiment_results = [] try: articles = fetch_news(ticker) for title, desc in articles: - sentiment = analyze_sentiment(title + ' ' + str(desc)) + sentiment = analyze_sentiment(title + " " + str(desc)) sentiment_results.append(sentiment) - st.write(f'**{title}** - Sentiment: {sentiment}') + st.write(f"**{title}** - Sentiment: {sentiment}") if sentiment_results: plot_sentiment_summary(sentiment_results) except Exception as e: - st.warning(f'Cannot fetch real news: {e}') \ No newline at end of file + st.warning(f"Cannot fetch real news: {e}") diff --git a/src/fetch_news.py b/src/fetch_news.py index 7462ace..a253b11 100644 --- a/src/fetch_news.py +++ b/src/fetch_news.py @@ -5,12 +5,16 @@ dotenv.load_dotenv() + def fetch_news(query, page_size=10): """Fetch latest news articles using NewsAPI""" - api_key = os.getenv('NEWS_API_KEY') + api_key = os.getenv("NEWS_API_KEY") if not api_key: - raise ValueError('Please set NEWS_API_KEY in .env file') - url = f'https://newsapi.org/v2/everything?q={query}&pageSize={page_size}&apiKey={api_key}' + raise ValueError("Please set NEWS_API_KEY in .env file") + url = ( + f"https://newsapi.org/v2/everything?q={query}&" + f"pageSize={page_size}&apiKey={api_key}" + ) response = requests.get(url) - articles = response.json().get('articles', []) - return [(a['title'], a['description']) for a in articles] \ No newline at end of file + articles = response.json().get("articles", []) + return [(a["title"], a["description"]) for a in articles] diff --git a/src/fetch_stock.py b/src/fetch_stock.py index 1b30a70..cff2206 100644 --- a/src/fetch_stock.py +++ b/src/fetch_stock.py @@ -1,7 +1,7 @@ import yfinance as yf -def get_stock_data(ticker, period='1d', interval='1m'): +def get_stock_data(ticker, period="1d", interval="1m"): stock = yf.Ticker(ticker) data = stock.history(period=period, interval=interval) - return data \ No newline at end of file + return data diff --git a/src/sentiment.py b/src/sentiment.py index ad8ca2b..b4e4be8 100644 --- a/src/sentiment.py +++ b/src/sentiment.py @@ -4,8 +4,8 @@ def analyze_sentiment(text): polarity = TextBlob(text).sentiment.polarity if polarity > 0: - return 'positive' + return "positive" elif polarity < 0: - return 'negative' + return "negative" else: - return 'neutral' \ No newline at end of file + return "neutral" diff --git a/src/visualization.py b/src/visualization.py index 0ca394c..e38c483 100644 --- a/src/visualization.py +++ b/src/visualization.py @@ -3,23 +3,23 @@ def plot_stock(data, ticker): - plt.figure(figsize=(10,5)) - plt.plot(data.index, data['Close'], label=f'{ticker} Close Price') - plt.xlabel('Time') - plt.ylabel('Price') - plt.title(f'{ticker} Stock Price') + plt.figure(figsize=(10, 5)) + plt.plot(data.index, data["Close"], label=f"{ticker} Close Price") + plt.xlabel("Time") + plt.ylabel("Price") + plt.title(f"{ticker} Stock Price") plt.legend() st.pyplot(plt) def plot_sentiment_summary(sentiment_list): - counts = {'positive': 0, 'negative': 0, 'neutral': 0} + counts = {"positive": 0, "negative": 0, "neutral": 0} for s in sentiment_list: counts[s] += 1 labels = counts.keys() values = counts.values() fig, ax = plt.subplots() - ax.bar(labels, values, color=['green', 'red', 'gray']) - ax.set_ylabel('Count') - ax.set_title('News Sentiment Summary') - st.pyplot(fig) \ No newline at end of file + ax.bar(labels, values, color=["green", "red", "gray"]) + ax.set_ylabel("Count") + ax.set_title("News Sentiment Summary") + st.pyplot(fig) From 9b662c70339ab68b0b4760acf4c50db0c7ba0615 Mon Sep 17 00:00:00 2001 From: Shrividya Hegde Date: Thu, 18 Dec 2025 16:32:06 -0500 Subject: [PATCH 2/2] chore: add improvements --- .github/workflows/python-app.yaml | 4 +++ src/__init__.py | 0 src/app.py | 4 ++- src/fetch_news.py | 25 ++++++++++++------ src/visualization.py | 43 ++++++++++++++++++++++++++++--- 5 files changed, 64 insertions(+), 12 deletions(-) create mode 100644 src/__init__.py diff --git a/.github/workflows/python-app.yaml b/.github/workflows/python-app.yaml index 40443e7..6193574 100644 --- a/.github/workflows/python-app.yaml +++ b/.github/workflows/python-app.yaml @@ -23,6 +23,10 @@ jobs: run: | python -m pip install --upgrade pip pip install -r requirements.txt + - name: Run with black + run: + pip install black + black . --line-length=78 - name: Lint with flake8 run: | pip install flake8 diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/app.py b/src/app.py index 3c4283a..bc2784f 100644 --- a/src/app.py +++ b/src/app.py @@ -27,7 +27,9 @@ data = pd.read_csv("data/sample_stock.csv") data.columns = data.columns.str.strip() # Remove any spaces print(data.columns) - data = pd.read_csv("data/sample_stock.csv", parse_dates=["Date"], index_col="Date") + data = pd.read_csv( + "data/sample_stock.csv", parse_dates=["Date"], index_col="Date" + ) st.line_chart(data["Close"]) st.subheader("Latest News Sentiment") sentiment_results = [] diff --git a/src/fetch_news.py b/src/fetch_news.py index a253b11..de41e8c 100644 --- a/src/fetch_news.py +++ b/src/fetch_news.py @@ -7,14 +7,23 @@ def fetch_news(query, page_size=10): - """Fetch latest news articles using NewsAPI""" api_key = os.getenv("NEWS_API_KEY") if not api_key: - raise ValueError("Please set NEWS_API_KEY in .env file") - url = ( - f"https://newsapi.org/v2/everything?q={query}&" - f"pageSize={page_size}&apiKey={api_key}" - ) - response = requests.get(url) + raise RuntimeError("NEWS_API_KEY not found") + + url = "https://newsapi.org/v2/everything" + params = { + "q": query, + "pageSize": page_size, + "apiKey": api_key, + "language": "en", + "sortBy": "publishedAt", + } + + headers = {"User-Agent": "StockSentimentAnalyzer/1.0"} + + response = requests.get(url, params=params, headers=headers) + response.raise_for_status() + articles = response.json().get("articles", []) - return [(a["title"], a["description"]) for a in articles] + return [(a["title"], a.get("description", "")) for a in articles] diff --git a/src/visualization.py b/src/visualization.py index e38c483..d194378 100644 --- a/src/visualization.py +++ b/src/visualization.py @@ -1,13 +1,50 @@ import matplotlib.pyplot as plt +import matplotlib.dates as mdates import streamlit as st def plot_stock(data, ticker): plt.figure(figsize=(10, 5)) - plt.plot(data.index, data["Close"], label=f"{ticker} Close Price") - plt.xlabel("Time") + + # Get today's high, low, and current price + today_high = data["High"].iloc[-1] + today_low = data["Low"].iloc[-1] + current_price = data["Close"].iloc[-1] + + # Plot current price as a horizontal line + plt.hlines( + current_price, + xmin=data.index[0], + xmax=data.index[-1], + colors="red", + linewidth=2, + label=f"Current Price: {current_price:.2f}", + ) + + # Set y-axis limits to today's low/high with padding + plt.ylim(today_low * 0.995, today_high * 1.005) + + # Format x-axis with ticks every 2 hours + ax = plt.gca() + + # 2-hour interval + ax.xaxis.set_major_locator(mdates.HourLocator(interval=2)) + ax.xaxis.set_major_formatter(mdates.DateFormatter("%H:%M")) + plt.xticks(rotation=45) + + # Annotate current price + plt.text( + data.index[len(data) // 2], + current_price * 1.001, + f"{current_price:.2f}", + color="red", + fontsize=12, + ha="center", + ) + plt.ylabel("Price") - plt.title(f"{ticker} Stock Price") + plt.xlabel("Time (Market Hours)") + plt.title(f"{ticker} Price Today") plt.legend() st.pyplot(plt)