Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/python-app.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Empty file added src/__init__.py
Empty file.
30 changes: 16 additions & 14 deletions src/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,36 +8,38 @@
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}')
st.warning(f"Cannot fetch real news: {e}")
27 changes: 20 additions & 7 deletions src/fetch_news.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,25 @@

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}'
response = requests.get(url)
articles = response.json().get('articles', [])
return [(a['title'], a['description']) for a in articles]
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.get("description", "")) for a in articles]
4 changes: 2 additions & 2 deletions src/fetch_stock.py
Original file line number Diff line number Diff line change
@@ -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
return data
6 changes: 3 additions & 3 deletions src/sentiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'
return "neutral"
57 changes: 47 additions & 10 deletions src/visualization.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,62 @@
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')
plt.ylabel('Price')
plt.title(f'{ticker} Stock Price')
plt.figure(figsize=(10, 5))

# 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.xlabel("Time (Market Hours)")
plt.title(f"{ticker} Price Today")
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)
ax.bar(labels, values, color=["green", "red", "gray"])
ax.set_ylabel("Count")
ax.set_title("News Sentiment Summary")
st.pyplot(fig)
Loading