Spaces:
Sleeping
Sleeping
Upload 11 files
Browse files- app.py +58 -0
- auth.py +49 -0
- data_fetcher.py +21 -0
- generated-icon.png +0 -0
- integrations.py +43 -0
- main.py +57 -0
- pyproject.toml +17 -0
- requirements.txt +17 -0
- styles.py +45 -0
- uv.lock +0 -0
- visualization.py +45 -0
app.py
ADDED
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Renaming main.py to app.py for Hugging Face compatibility
|
2 |
+
import streamlit as st
|
3 |
+
import plotly.graph_objects as go
|
4 |
+
import yfinance as yf
|
5 |
+
import pandas as pd
|
6 |
+
from datetime import datetime, timedelta
|
7 |
+
from data_fetcher import get_stock_data, get_company_info
|
8 |
+
from visualization import create_stock_chart, create_metrics_table
|
9 |
+
import styles
|
10 |
+
|
11 |
+
def main():
|
12 |
+
# Apply custom styles
|
13 |
+
styles.apply_custom_styles()
|
14 |
+
|
15 |
+
st.title("📈 Stock Analysis Terminal")
|
16 |
+
|
17 |
+
# Stock Symbol Input
|
18 |
+
symbol = st.text_input("Enter Stock Symbol (e.g., AAPL)", "").upper()
|
19 |
+
|
20 |
+
if symbol:
|
21 |
+
try:
|
22 |
+
# Fetch stock data
|
23 |
+
stock_data = get_stock_data(symbol)
|
24 |
+
company_info = get_company_info(symbol)
|
25 |
+
|
26 |
+
# Display company info
|
27 |
+
col1, col2 = st.columns(2)
|
28 |
+
with col1:
|
29 |
+
st.subheader(company_info.get('longName', symbol))
|
30 |
+
st.write(f"Sector: {company_info.get('sector', 'N/A')}")
|
31 |
+
with col2:
|
32 |
+
st.metric(
|
33 |
+
"Current Price",
|
34 |
+
f"${stock_data['Close'].iloc[-1]:.2f}",
|
35 |
+
f"{((stock_data['Close'].iloc[-1] / stock_data['Close'].iloc[-2]) - 1) * 100:.2f}%"
|
36 |
+
)
|
37 |
+
|
38 |
+
# Stock Chart
|
39 |
+
st.plotly_chart(create_stock_chart(stock_data, symbol), use_container_width=True)
|
40 |
+
|
41 |
+
# Financial Metrics Table
|
42 |
+
metrics_df = create_metrics_table(company_info)
|
43 |
+
st.dataframe(metrics_df, use_container_width=True)
|
44 |
+
|
45 |
+
# Download button for CSV
|
46 |
+
csv = stock_data.to_csv(index=True)
|
47 |
+
st.download_button(
|
48 |
+
label="Download Data as CSV",
|
49 |
+
data=csv,
|
50 |
+
file_name=f"{symbol}_stock_data.csv",
|
51 |
+
mime="text/csv"
|
52 |
+
)
|
53 |
+
|
54 |
+
except Exception as e:
|
55 |
+
st.error(f"Error retrieving data for {symbol}: {str(e)}")
|
56 |
+
|
57 |
+
if __name__ == "__main__":
|
58 |
+
main()
|
auth.py
ADDED
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import firebase_admin
|
3 |
+
from firebase_admin import credentials, auth
|
4 |
+
from firebase_admin import initialize_app
|
5 |
+
|
6 |
+
def initialize_firebase():
|
7 |
+
if not firebase_admin._apps:
|
8 |
+
cred = credentials.Certificate(st.secrets["firebase"])
|
9 |
+
initialize_app(cred)
|
10 |
+
|
11 |
+
def check_authentication():
|
12 |
+
initialize_firebase()
|
13 |
+
|
14 |
+
if 'user_authenticated' not in st.session_state:
|
15 |
+
st.session_state.user_authenticated = False
|
16 |
+
|
17 |
+
if not st.session_state.user_authenticated:
|
18 |
+
col1, col2 = st.columns(2)
|
19 |
+
|
20 |
+
with col1:
|
21 |
+
email = st.text_input("Email")
|
22 |
+
with col2:
|
23 |
+
password = st.text_input("Password", type="password")
|
24 |
+
|
25 |
+
col1, col2 = st.columns(2)
|
26 |
+
|
27 |
+
with col1:
|
28 |
+
if st.button("Login"):
|
29 |
+
try:
|
30 |
+
user = auth.get_user_by_email(email)
|
31 |
+
st.session_state.user_authenticated = True
|
32 |
+
st.experimental_rerun()
|
33 |
+
except:
|
34 |
+
st.error("Invalid credentials")
|
35 |
+
|
36 |
+
with col2:
|
37 |
+
if st.button("Sign Up"):
|
38 |
+
try:
|
39 |
+
user = auth.create_user(
|
40 |
+
email=email,
|
41 |
+
password=password
|
42 |
+
)
|
43 |
+
st.success("Account created successfully!")
|
44 |
+
except:
|
45 |
+
st.error("Could not create account")
|
46 |
+
|
47 |
+
return False
|
48 |
+
|
49 |
+
return True
|
data_fetcher.py
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import yfinance as yf
|
3 |
+
import pandas as pd
|
4 |
+
from datetime import datetime, timedelta
|
5 |
+
|
6 |
+
@st.cache_data(ttl=3600)
|
7 |
+
def get_stock_data(symbol):
|
8 |
+
"""Fetch stock data from Yahoo Finance"""
|
9 |
+
end_date = datetime.now()
|
10 |
+
start_date = end_date - timedelta(days=365)
|
11 |
+
|
12 |
+
stock = yf.Ticker(symbol)
|
13 |
+
df = stock.history(start=start_date, end=end_date)
|
14 |
+
|
15 |
+
return df
|
16 |
+
|
17 |
+
@st.cache_data(ttl=3600)
|
18 |
+
def get_company_info(symbol):
|
19 |
+
"""Fetch company information"""
|
20 |
+
stock = yf.Ticker(symbol)
|
21 |
+
return stock.info
|
generated-icon.png
ADDED
![]() |
integrations.py
ADDED
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
from google.oauth2.credentials import Credentials
|
3 |
+
from google_auth_oauthlib.flow import InstalledAppFlow
|
4 |
+
from googleapiclient.discovery import build
|
5 |
+
from datetime import datetime, timedelta
|
6 |
+
|
7 |
+
def add_to_google_calendar(symbol, company_name):
|
8 |
+
"""Add analysis review event to Google Calendar"""
|
9 |
+
creds = Credentials.from_authorized_user_info(st.secrets["google"])
|
10 |
+
service = build('calendar', 'v3', credentials=creds)
|
11 |
+
|
12 |
+
event = {
|
13 |
+
'summary': f'Stock Analysis Review - {symbol}',
|
14 |
+
'description': f'Review financial analysis for {company_name}',
|
15 |
+
'start': {
|
16 |
+
'dateTime': (datetime.now() + timedelta(days=1)).isoformat(),
|
17 |
+
'timeZone': 'UTC',
|
18 |
+
},
|
19 |
+
'end': {
|
20 |
+
'dateTime': (datetime.now() + timedelta(days=1, hours=1)).isoformat(),
|
21 |
+
'timeZone': 'UTC',
|
22 |
+
},
|
23 |
+
}
|
24 |
+
|
25 |
+
service.events().insert(calendarId='primary', body=event).execute()
|
26 |
+
|
27 |
+
def update_google_sheet(stock_data, symbol):
|
28 |
+
"""Export stock data to Google Sheets"""
|
29 |
+
creds = Credentials.from_authorized_user_info(st.secrets["google"])
|
30 |
+
service = build('sheets', 'v4', credentials=creds)
|
31 |
+
|
32 |
+
spreadsheet_id = st.secrets["google_sheet_id"]
|
33 |
+
range_name = f'{symbol}!A1'
|
34 |
+
|
35 |
+
values = [stock_data.columns.tolist()] + stock_data.reset_index().values.tolist()
|
36 |
+
body = {'values': values}
|
37 |
+
|
38 |
+
service.spreadsheets().values().update(
|
39 |
+
spreadsheetId=spreadsheet_id,
|
40 |
+
range=range_name,
|
41 |
+
valueInputOption='RAW',
|
42 |
+
body=body
|
43 |
+
).execute()
|
main.py
ADDED
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import plotly.graph_objects as go
|
3 |
+
import yfinance as yf
|
4 |
+
import pandas as pd
|
5 |
+
from datetime import datetime, timedelta
|
6 |
+
from data_fetcher import get_stock_data, get_company_info
|
7 |
+
from visualization import create_stock_chart, create_metrics_table
|
8 |
+
import styles
|
9 |
+
|
10 |
+
def main():
|
11 |
+
# Apply custom styles
|
12 |
+
styles.apply_custom_styles()
|
13 |
+
|
14 |
+
st.title("📈 Stock Analysis Terminal")
|
15 |
+
|
16 |
+
# Stock Symbol Input
|
17 |
+
symbol = st.text_input("Enter Stock Symbol (e.g., AAPL)", "").upper()
|
18 |
+
|
19 |
+
if symbol:
|
20 |
+
try:
|
21 |
+
# Fetch stock data
|
22 |
+
stock_data = get_stock_data(symbol)
|
23 |
+
company_info = get_company_info(symbol)
|
24 |
+
|
25 |
+
# Display company info
|
26 |
+
col1, col2 = st.columns(2)
|
27 |
+
with col1:
|
28 |
+
st.subheader(company_info.get('longName', symbol))
|
29 |
+
st.write(f"Sector: {company_info.get('sector', 'N/A')}")
|
30 |
+
with col2:
|
31 |
+
st.metric(
|
32 |
+
"Current Price",
|
33 |
+
f"${stock_data['Close'].iloc[-1]:.2f}",
|
34 |
+
f"{((stock_data['Close'].iloc[-1] / stock_data['Close'].iloc[-2]) - 1) * 100:.2f}%"
|
35 |
+
)
|
36 |
+
|
37 |
+
# Stock Chart
|
38 |
+
st.plotly_chart(create_stock_chart(stock_data, symbol), use_container_width=True)
|
39 |
+
|
40 |
+
# Financial Metrics Table
|
41 |
+
metrics_df = create_metrics_table(company_info)
|
42 |
+
st.dataframe(metrics_df, use_container_width=True)
|
43 |
+
|
44 |
+
# Download button for CSV
|
45 |
+
csv = stock_data.to_csv(index=True)
|
46 |
+
st.download_button(
|
47 |
+
label="Download Data as CSV",
|
48 |
+
data=csv,
|
49 |
+
file_name=f"{symbol}_stock_data.csv",
|
50 |
+
mime="text/csv"
|
51 |
+
)
|
52 |
+
|
53 |
+
except Exception as e:
|
54 |
+
st.error(f"Error retrieving data for {symbol}: {str(e)}")
|
55 |
+
|
56 |
+
if __name__ == "__main__":
|
57 |
+
main()
|
pyproject.toml
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[project]
|
2 |
+
name = "repl-nix-workspace"
|
3 |
+
version = "0.1.0"
|
4 |
+
description = "Add your description here"
|
5 |
+
requires-python = ">=3.11"
|
6 |
+
dependencies = [
|
7 |
+
"firebase-admin>=6.6.0",
|
8 |
+
"google-api-python-client>=2.159.0",
|
9 |
+
"google-auth>=2.37.0",
|
10 |
+
"google-auth-oauthlib>=1.2.1",
|
11 |
+
"huggingface-hub>=0.27.1",
|
12 |
+
"pandas>=2.2.3",
|
13 |
+
"plotly>=5.24.1",
|
14 |
+
"streamlit>=1.41.1",
|
15 |
+
"telegram>=0.0.1",
|
16 |
+
"yfinance>=0.2.52",
|
17 |
+
]
|
requirements.txt
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
streamlit
|
2 |
+
yfinance
|
3 |
+
pandas
|
4 |
+
plotly
|
5 |
+
firebase-admin
|
6 |
+
google-api-python-client
|
7 |
+
google-auth-oauthlib
|
8 |
+
huggingface-hub
|
9 |
+
firebase-admin
|
10 |
+
google-api-python-client
|
11 |
+
google-auth
|
12 |
+
google-auth-oauthlib
|
13 |
+
huggingface-hub
|
14 |
+
pandas
|
15 |
+
plotly
|
16 |
+
streamlit
|
17 |
+
yfinance
|
styles.py
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
|
3 |
+
def apply_custom_styles():
|
4 |
+
"""Apply custom CSS styles to the application"""
|
5 |
+
st.markdown("""
|
6 |
+
<style>
|
7 |
+
.stApp {
|
8 |
+
max-width: 1200px;
|
9 |
+
margin: 0 auto;
|
10 |
+
}
|
11 |
+
|
12 |
+
.stTextInput > div > div > input {
|
13 |
+
background-color: #1E1E1E;
|
14 |
+
color: #FFFFFF;
|
15 |
+
border: 1px solid #4A4A4A;
|
16 |
+
}
|
17 |
+
|
18 |
+
.stDataFrame {
|
19 |
+
background-color: #1E1E1E;
|
20 |
+
}
|
21 |
+
|
22 |
+
.stButton > button {
|
23 |
+
background-color: #FF4B4B;
|
24 |
+
color: white;
|
25 |
+
border: none;
|
26 |
+
border-radius: 4px;
|
27 |
+
padding: 0.5rem 1rem;
|
28 |
+
}
|
29 |
+
|
30 |
+
.stButton > button:hover {
|
31 |
+
background-color: #FF6B6B;
|
32 |
+
}
|
33 |
+
|
34 |
+
h1, h2, h3 {
|
35 |
+
color: #FFFFFF;
|
36 |
+
}
|
37 |
+
|
38 |
+
.metric-card {
|
39 |
+
background-color: #262730;
|
40 |
+
padding: 1rem;
|
41 |
+
border-radius: 8px;
|
42 |
+
margin: 0.5rem 0;
|
43 |
+
}
|
44 |
+
</style>
|
45 |
+
""", unsafe_allow_html=True)
|
uv.lock
ADDED
The diff for this file is too large to render.
See raw diff
|
|
visualization.py
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import plotly.graph_objects as go
|
2 |
+
import pandas as pd
|
3 |
+
|
4 |
+
def create_stock_chart(stock_data, symbol):
|
5 |
+
"""Create an interactive stock price chart"""
|
6 |
+
fig = go.Figure()
|
7 |
+
|
8 |
+
fig.add_trace(
|
9 |
+
go.Candlestick(
|
10 |
+
x=stock_data.index,
|
11 |
+
open=stock_data['Open'],
|
12 |
+
high=stock_data['High'],
|
13 |
+
low=stock_data['Low'],
|
14 |
+
close=stock_data['Close'],
|
15 |
+
name=symbol
|
16 |
+
)
|
17 |
+
)
|
18 |
+
|
19 |
+
fig.update_layout(
|
20 |
+
title=f"{symbol} Stock Price",
|
21 |
+
yaxis_title="Price (USD)",
|
22 |
+
template="plotly_dark",
|
23 |
+
xaxis_rangeslider_visible=False
|
24 |
+
)
|
25 |
+
|
26 |
+
return fig
|
27 |
+
|
28 |
+
def create_metrics_table(company_info):
|
29 |
+
"""Create a table of key financial metrics"""
|
30 |
+
metrics = {
|
31 |
+
'Metric': [
|
32 |
+
'Market Cap', 'P/E Ratio', 'Forward P/E',
|
33 |
+
'PEG Ratio', 'Dividend Yield', 'Beta'
|
34 |
+
],
|
35 |
+
'Value': [
|
36 |
+
company_info.get('marketCap', 'N/A'),
|
37 |
+
company_info.get('trailingPE', 'N/A'),
|
38 |
+
company_info.get('forwardPE', 'N/A'),
|
39 |
+
company_info.get('pegRatio', 'N/A'),
|
40 |
+
company_info.get('dividendYield', 'N/A'),
|
41 |
+
company_info.get('beta', 'N/A')
|
42 |
+
]
|
43 |
+
}
|
44 |
+
|
45 |
+
return pd.DataFrame(metrics)
|