Upload main.py
Browse filesupdating the file
main.py
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import yfinance as yf
|
| 3 |
+
import plotly.graph_objects as go
|
| 4 |
+
from prophet import Prophet
|
| 5 |
+
import pandas as pd
|
| 6 |
+
import matplotlib.pyplot as plt
|
| 7 |
+
from statsmodels.tsa.seasonal import seasonal_decompose
|
| 8 |
+
|
| 9 |
+
from statsmodels.graphics.gofplots import qqplot
|
| 10 |
+
|
| 11 |
+
# Set Streamlit options
|
| 12 |
+
st.set_page_config(layout="wide") # Use wide page layout
|
| 13 |
+
st.set_option('deprecation.showPyplotGlobalUse', False)
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
# Header section with enhanced aesthetics
|
| 17 |
+
def display_header():
|
| 18 |
+
st.sidebar.title("Navigation")
|
| 19 |
+
st.sidebar.info("""
|
| 20 |
+
This application is designed to provide users with financial insights and predictive analysis
|
| 21 |
+
on various stocks using real-time data from Yahoo Finance. Created by Gokul Palanisamy.
|
| 22 |
+
""")
|
| 23 |
+
st.sidebar.title("About Us")
|
| 24 |
+
st.sidebar.info("""
|
| 25 |
+
Developed by Gokul Palanisamy, this tool helps users make informed investment decisions by
|
| 26 |
+
analyzing historical data and predicting future stock trends.
|
| 27 |
+
""")
|
| 28 |
+
st.sidebar.title("Contact Us")
|
| 29 |
+
st.sidebar.info("""
|
| 30 |
+
Email: [gokulp@bu.edu](mailto:gokulp@bu.edu)
|
| 31 |
+
Phone: +1 (857) 832-0441
|
| 32 |
+
More Information: [Gokul Palanisamy](https://www.linkedin.com/in/gokulp/)
|
| 33 |
+
""")
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
display_header()
|
| 37 |
+
|
| 38 |
+
# Input widgets for stock symbols and settings
|
| 39 |
+
st.markdown("## StocX AI")
|
| 40 |
+
col1, col2, col3 = st.columns(3)
|
| 41 |
+
with col1:
|
| 42 |
+
stock1 = st.text_input('Enter Stock Ticker Symbol 1', value='', key='stock1_input')
|
| 43 |
+
with col2:
|
| 44 |
+
stock2 = st.text_input('Enter Stock Ticker Symbol 2', value='', key='stock2_input')
|
| 45 |
+
with col3:
|
| 46 |
+
daysago = st.text_input('Select Time Frame in Days (write "max" for maximum time)', value='1y', key='daysago_input')
|
| 47 |
+
forecast_out = st.slider('Predicted Days Ahead', 1, 180, 30)
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
# Fetch and display stock data
|
| 51 |
+
def fetch_data(ticker, period):
|
| 52 |
+
return yf.Ticker(ticker).history(period=period)
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
data1, data2 = None, None
|
| 56 |
+
if stock1:
|
| 57 |
+
data1 = fetch_data(stock1, daysago)
|
| 58 |
+
st.write(f'### {stock1} Stock Data')
|
| 59 |
+
st.write(data1)
|
| 60 |
+
|
| 61 |
+
if stock2:
|
| 62 |
+
data2 = fetch_data(stock2, daysago)
|
| 63 |
+
st.write(f'### {stock2} Stock Data')
|
| 64 |
+
st.write(data2)
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
# Function to analyze and compare stocks
|
| 68 |
+
def compare_stocks(stock1, data1, stock2, data2):
|
| 69 |
+
if data1 is not None and data2 is not None:
|
| 70 |
+
# Calculate percentage change for each stock
|
| 71 |
+
pct_change1 = (data1['Close'].iloc[-1] - data1['Close'].iloc[0]) / data1['Close'].iloc[0] * 100
|
| 72 |
+
pct_change2 = (data2['Close'].iloc[-1] - data2['Close'].iloc[0]) / data2['Close'].iloc[0] * 100
|
| 73 |
+
|
| 74 |
+
better_stock = stock1 if pct_change1 > pct_change2 else stock2
|
| 75 |
+
reason = f"{better_stock} had a higher percentage change ({max(pct_change1, pct_change2):.2f}%) over the period."
|
| 76 |
+
|
| 77 |
+
st.write("## Stock Performance Comparison")
|
| 78 |
+
st.write(f"**{stock1}** percentage change: {pct_change1:.2f}%")
|
| 79 |
+
st.write(f"**{stock2}** percentage change: {pct_change2:.2f}%")
|
| 80 |
+
st.write(f"**Better Performing Stock:** {better_stock}")
|
| 81 |
+
st.write(f"**Reason:** {reason}")
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
if stock1 and stock2 and data1 is not None and data2 is not None:
|
| 85 |
+
compare_stocks(stock1, data1, stock2, data2)
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
# Comprehensive analysis functions
|
| 89 |
+
def perform_analysis(stock, data):
|
| 90 |
+
if data is not None and not data.empty:
|
| 91 |
+
st.write(f"### {stock} Detailed Analysis")
|
| 92 |
+
|
| 93 |
+
# Time Series Decomposition
|
| 94 |
+
st.write(f"#### Time Series Decomposition")
|
| 95 |
+
decomposition = seasonal_decompose(data['Close'], period=30, model='additive')
|
| 96 |
+
fig, (ax1, ax2, ax3, ax4) = plt.subplots(4, 1, figsize=(10, 8))
|
| 97 |
+
decomposition.observed.plot(ax=ax1, title='Observed')
|
| 98 |
+
decomposition.trend.plot(ax=ax2, title='Trend')
|
| 99 |
+
decomposition.seasonal.plot(ax=ax3, title='Seasonal')
|
| 100 |
+
decomposition.resid.plot(ax=ax4, title='Residual')
|
| 101 |
+
plt.tight_layout()
|
| 102 |
+
st.pyplot()
|
| 103 |
+
|
| 104 |
+
# Prophet Prediction
|
| 105 |
+
st.write(f"#### Prophet Forecast")
|
| 106 |
+
df_prophet = pd.DataFrame(data={'ds': data.index, 'y': data['Close']})
|
| 107 |
+
df_prophet['ds'] = pd.to_datetime(df_prophet['ds']).dt.tz_localize(None) # Make timezone naive
|
| 108 |
+
model = Prophet()
|
| 109 |
+
model.fit(df_prophet)
|
| 110 |
+
future = model.make_future_dataframe(periods=forecast_out)
|
| 111 |
+
forecast = model.predict(future)
|
| 112 |
+
fig = plot_prophet_forecast(model, forecast)
|
| 113 |
+
st.plotly_chart(fig)
|
| 114 |
+
|
| 115 |
+
|
| 116 |
+
# Helper function for Plotly forecast visualization
|
| 117 |
+
def plot_prophet_forecast(model, forecast):
|
| 118 |
+
fig = go.Figure()
|
| 119 |
+
fig.add_trace(go.Scatter(x=model.history['ds'], y=model.history['y'], mode='lines', name='Actual'))
|
| 120 |
+
fig.add_trace(go.Scatter(x=forecast['ds'], y=forecast['yhat'], mode='lines+markers', name='Forecast'))
|
| 121 |
+
fig.add_trace(go.Scatter(x=forecast['ds'], y=forecast['yhat_upper'], fill=None, mode='lines',
|
| 122 |
+
line=dict(color='gray', dash='dash'), name='Upper Confidence Interval'))
|
| 123 |
+
fig.add_trace(go.Scatter(x=forecast['ds'], y=forecast['yhat_lower'], fill='tonexty', mode='lines',
|
| 124 |
+
line=dict(color='gray', dash='dash'), name='Lower Confidence Interval'))
|
| 125 |
+
fig.update_layout(title='Prophet Forecast and Confidence Intervals', xaxis_title='Date', yaxis_title='Values',
|
| 126 |
+
hovermode='x')
|
| 127 |
+
return fig
|
| 128 |
+
|
| 129 |
+
|
| 130 |
+
# Call analysis functions if data is available
|
| 131 |
+
if stock1 and data1 is not None:
|
| 132 |
+
perform_analysis(stock1, data1)
|
| 133 |
+
if stock2 and data2 is not None:
|
| 134 |
+
perform_analysis(stock2, data2)
|