Spaces:
Sleeping
Sleeping
Upload 3 files
Browse files- app.py +8 -515
- pages/π_Stock_Analysis.py +516 -0
- pages/π_Stock_Comparison.py +63 -0
app.py
CHANGED
|
@@ -1,518 +1,11 @@
|
|
| 1 |
-
|
| 2 |
-
import pandas as pd
|
| 3 |
-
import numpy as np
|
| 4 |
-
import matplotlib.pyplot as plt
|
| 5 |
-
import pandas_datareader.data as web
|
| 6 |
-
import datetime as dt
|
| 7 |
-
import yfinance as yf
|
| 8 |
-
from sklearn.preprocessing import MinMaxScaler
|
| 9 |
-
from keras.models import load_model
|
| 10 |
import streamlit as st
|
| 11 |
-
import streamlit as st
|
| 12 |
-
import plotly.graph_objects as go
|
| 13 |
-
import base64
|
| 14 |
-
import plotly.express as px
|
| 15 |
-
from datetime import datetime
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
## ............................................... ##
|
| 19 |
-
# Set page configuration (Call this once and make changes as needed)
|
| 20 |
-
st.set_page_config(page_title='Regression Stocks Prediction', layout='wide', page_icon=':rocket:')
|
| 21 |
-
|
| 22 |
-
## ............................................... ##
|
| 23 |
-
# Add a dictonary of stock tickers and their company names and make a drop down menu to select the stock to predict
|
| 24 |
-
stock_tickers = {
|
| 25 |
-
"MAPI":"MAPI.JK","MAP Aktif": "MAPA.JK","MAP Boga": "MAPB.JK",
|
| 26 |
-
"Tesla": "TSLA", "Apple": "AAPL", "Microsoft": "MSFT", "Google": "GOOGL",
|
| 27 |
-
"Meta": "META", "Amazon": "AMZN", "Netflix": "NFLX", "Alphabet": "GOOG",
|
| 28 |
-
"Nvidia": "NVDA", "Paypal": "PYPL", "Adobe": "ADBE", "Intel": "INTC",
|
| 29 |
-
"Cisco": "CSCO", "Comcast": "CMCSA", "Pepsi": "PEP", "Costco": "COST",
|
| 30 |
-
"Starbucks": "SBUX", "Walmart": "WMT", "Disney": "DIS", "Visa": "V",
|
| 31 |
-
"Mastercard": "MA", "Boeing": "BA", "IBM": "IBM", "McDonalds": "MCD",
|
| 32 |
-
"Nike": "NKE", "Exxon": "XOM", "Chevron": "CVX", "Verizon": "VZ",
|
| 33 |
-
"AT&T": "T", "Home Depot": "HD", "Salesforce": "CRM", "Oracle": "ORCL",
|
| 34 |
-
"Qualcomm": "QCOM", "AMD": "AMD"
|
| 35 |
-
}
|
| 36 |
-
|
| 37 |
-
st.sidebar.title("Stock Option")
|
| 38 |
-
# Custom CSS to change the sidebar color
|
| 39 |
-
sidebar_css = """
|
| 40 |
-
<style>
|
| 41 |
-
div[data-testid="stSidebar"] > div:first-child {
|
| 42 |
-
width: 350px; # Adjust the width as needed
|
| 43 |
-
background-color: #FF6969;
|
| 44 |
-
}
|
| 45 |
-
</style>
|
| 46 |
-
"""
|
| 47 |
-
|
| 48 |
-
# User Input
|
| 49 |
-
#default_index = stock_tickers.keys().index("MAPI.JK") if "MAPI.JK" in stock_tickers.keys() else 0
|
| 50 |
-
#st.markdown(sidebar_css, unsafe_allow_html=True)
|
| 51 |
-
#user_input = st.sidebar.selectbox("Select a Stock", list(stock_tickers.keys()), index=default_index , key="main_selectbox")
|
| 52 |
-
#stock_name = user_input
|
| 53 |
-
#user_input = stock_tickers[user_input]
|
| 54 |
-
|
| 55 |
-
user_input = st.sidebar.text_input("Select a Stock", "MAPI.JK")
|
| 56 |
-
|
| 57 |
-
# User input for start and end dates using calendar widget
|
| 58 |
-
start_date = st.sidebar.date_input("Select start date:", datetime(2023, 1, 1))
|
| 59 |
-
end_date = st.sidebar.date_input("Select end date:", datetime(2023, 12, 1))
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
st.sidebar.markdown("----")
|
| 63 |
-
st.sidebar.markdown("Β© 2023 Stocks Prediction App")
|
| 64 |
-
st.sidebar.markdown("----")
|
| 65 |
-
st.sidebar.markdown("Example Stock Tickers")
|
| 66 |
-
st.sidebar.markdown(stock_tickers)
|
| 67 |
-
|
| 68 |
-
## ............................................... ##
|
| 69 |
-
# Page Title and Description
|
| 70 |
-
st.title("Stock Price Analysis and Prediction")
|
| 71 |
-
st.write("Created by Bayhaqy")
|
| 72 |
-
st.write("Using Dataset MAPI to Train and Test the Model")
|
| 73 |
-
|
| 74 |
-
## ............................................... ##
|
| 75 |
-
|
| 76 |
-
# Try to fetch information from Yahoo Finance
|
| 77 |
-
try:
|
| 78 |
-
stock_info = yf.Ticker(user_input).info
|
| 79 |
-
|
| 80 |
-
# Check if the 'longName' key exists in stock_info
|
| 81 |
-
if 'longName' in stock_info:
|
| 82 |
-
stock_name = stock_info['longName']
|
| 83 |
-
else:
|
| 84 |
-
stock_name = user_input
|
| 85 |
-
|
| 86 |
-
# Fetch the latest news using yfinance
|
| 87 |
-
news_data = yf.Ticker(user_input).news
|
| 88 |
-
|
| 89 |
-
# Create a Streamlit app
|
| 90 |
-
title = f"<h1 style='color: red; font-size: 25px; text-align: center; '>{stock_name}'s Stock Fundamental Analysis</h1>"
|
| 91 |
-
st.markdown(title, unsafe_allow_html=True)
|
| 92 |
-
|
| 93 |
-
with st.expander("See Details"):
|
| 94 |
-
## ............................................... ##
|
| 95 |
-
# Display the retrieved stock information
|
| 96 |
-
if 'longName' in stock_info:
|
| 97 |
-
company_name = stock_info['longName']
|
| 98 |
-
st.write(f"Company Name: {company_name}")
|
| 99 |
-
else:
|
| 100 |
-
st.write("Company name information not available for this stock.")
|
| 101 |
-
|
| 102 |
-
if 'industry' in stock_info:
|
| 103 |
-
Industry = stock_info['industry']
|
| 104 |
-
st.write(f"Industry: {Industry}")
|
| 105 |
-
else:
|
| 106 |
-
st.write("Industry information not available for this stock.")
|
| 107 |
-
|
| 108 |
-
if 'sector' in stock_info:
|
| 109 |
-
Sector = stock_info['sector']
|
| 110 |
-
st.write(f"Sector: {Sector}")
|
| 111 |
-
else:
|
| 112 |
-
st.write("Sector information not available for this stock.")
|
| 113 |
-
|
| 114 |
-
if 'website' in stock_info:
|
| 115 |
-
Website = stock_info['website']
|
| 116 |
-
st.write(f"Sector: {Website}")
|
| 117 |
-
else:
|
| 118 |
-
st.write("Website information not available for this stock.")
|
| 119 |
-
|
| 120 |
-
if 'marketCap' in stock_info:
|
| 121 |
-
MarketCap = stock_info['marketCap']
|
| 122 |
-
st.write(f"Market Cap: {MarketCap}")
|
| 123 |
-
else:
|
| 124 |
-
st.write("Market Cap information not available for this stock.")
|
| 125 |
-
|
| 126 |
-
if 'previousClose' in stock_info:
|
| 127 |
-
PreviousClose = stock_info['previousClose']
|
| 128 |
-
st.write(f"Previous Close: {PreviousClose}")
|
| 129 |
-
else:
|
| 130 |
-
st.write("Previous Close information not available for this stock.")
|
| 131 |
-
|
| 132 |
-
if 'dividendYield' in stock_info:
|
| 133 |
-
dividend_yield = stock_info['dividendYield'] * 100 # Convert to percentage
|
| 134 |
-
st.write(f"Dividend Yield: {dividend_yield:.2f}%")
|
| 135 |
-
else:
|
| 136 |
-
st.write("Dividend Yield information not available for this stock.")
|
| 137 |
-
|
| 138 |
-
## ............................................... ##
|
| 139 |
-
# Display financial metrics
|
| 140 |
-
st.subheader('Financial Metrics')
|
| 141 |
-
if 'trailingEps' in stock_info:
|
| 142 |
-
trailing_eps = stock_info['trailingEps']
|
| 143 |
-
st.write(f"Earnings Per Share (EPS): {trailing_eps:.2f}")
|
| 144 |
-
else:
|
| 145 |
-
st.write("Earnings Per Share (EPS) information not available for this stock.")
|
| 146 |
-
|
| 147 |
-
if 'trailingPE' in stock_info:
|
| 148 |
-
trailing_pe = stock_info['trailingPE']
|
| 149 |
-
st.write(f"Price-to-Earnings (P/E) Ratio: {trailing_pe:.2f}")
|
| 150 |
-
else:
|
| 151 |
-
st.write("Price-to-Earnings (P/E) Ratio information not available for this stock.")
|
| 152 |
-
|
| 153 |
-
if 'priceToSalesTrailing12Months' in stock_info:
|
| 154 |
-
priceToSalesTrailing_12Months = stock_info['priceToSalesTrailing12Months']
|
| 155 |
-
st.write(f"Price-to-Sales (P/S) Ratio: {priceToSalesTrailing_12Months:.2f}")
|
| 156 |
-
else:
|
| 157 |
-
st.write("Price-to-Sales (P/S) Ratio information not available for this stock.")
|
| 158 |
-
|
| 159 |
-
if 'priceToBook' in stock_info:
|
| 160 |
-
price_ToBook = stock_info['priceToBook']
|
| 161 |
-
st.write(f"Price-to-Book (P/B) Ratio: {price_ToBook:.2f}")
|
| 162 |
-
else:
|
| 163 |
-
st.write("Price-to-Book (P/B) Ratio information not available for this stock.")
|
| 164 |
-
|
| 165 |
-
## ............................................... ##
|
| 166 |
-
# Display more detailed information
|
| 167 |
-
st.subheader('Company Summary')
|
| 168 |
-
if 'longBusinessSummary' in stock_info:
|
| 169 |
-
LongBusinessSummary = stock_info['longBusinessSummary']
|
| 170 |
-
st.write(f"Company Summary: {LongBusinessSummary}")
|
| 171 |
-
else:
|
| 172 |
-
st.write("Company Summary information not available for this stock.")
|
| 173 |
-
|
| 174 |
-
## ............................................... ##
|
| 175 |
-
# Display information about company officers
|
| 176 |
-
st.subheader('Company Officers')
|
| 177 |
-
if 'fullTimeEmployees' in stock_info:
|
| 178 |
-
FullTimeEmployees = stock_info['fullTimeEmployees']
|
| 179 |
-
st.write(f"Full Time Employees: {FullTimeEmployees}")
|
| 180 |
-
else:
|
| 181 |
-
st.write("Full Time Employees information not available for this stock.")
|
| 182 |
-
|
| 183 |
-
if 'companyOfficers' in stock_info:
|
| 184 |
-
officers = stock_info['companyOfficers']
|
| 185 |
-
officer_data = []
|
| 186 |
-
|
| 187 |
-
# Create a DataFrame
|
| 188 |
-
df = pd.DataFrame(columns=["Name", "Title", "Age"])
|
| 189 |
-
|
| 190 |
-
# Populate the DataFrame with officer information
|
| 191 |
-
#for officer in officers:
|
| 192 |
-
# officer_data.append([officer['name'], officer['title'], officer['age']])
|
| 193 |
-
|
| 194 |
-
for officer in officers:
|
| 195 |
-
name = officer.get('name', 'N/A')
|
| 196 |
-
title = officer.get('title', 'N/A')
|
| 197 |
-
age = officer.get('age', 'N/A')
|
| 198 |
-
officer_data.append([name, title, age])
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
df = pd.concat([df, pd.DataFrame(officer_data, columns=["Name", "Title", "Age"])], ignore_index=True)
|
| 202 |
-
|
| 203 |
-
# Display the DataFrame using Markdown without the index column
|
| 204 |
-
st.markdown(df.to_markdown(index=False))
|
| 205 |
-
|
| 206 |
-
else:
|
| 207 |
-
st.write("Company Officers information not available for this stock.")
|
| 208 |
-
|
| 209 |
-
## ............................................... ##
|
| 210 |
-
# Display the latest news
|
| 211 |
-
st.subheader('Latest News')
|
| 212 |
-
|
| 213 |
-
# Prepare the data for the DataFrame
|
| 214 |
-
news_data_for_dataframe = []
|
| 215 |
-
for news_item in news_data:
|
| 216 |
-
news_title = news_item['title']
|
| 217 |
-
news_link = f"[Link]({news_item['link']})"
|
| 218 |
-
news_publisher = news_item['publisher']
|
| 219 |
-
news_provider_publish_time = pd.to_datetime(news_item['providerPublishTime'], unit='s')
|
| 220 |
-
news_type = news_item['type']
|
| 221 |
-
news_data_for_dataframe.append([news_title, news_link, news_publisher, news_provider_publish_time, news_type])
|
| 222 |
-
|
| 223 |
-
# Create a Pandas DataFrame
|
| 224 |
-
df = pd.DataFrame(news_data_for_dataframe, columns=["Title", "Link", "Publisher", "Provider Publish Time", "Type"])
|
| 225 |
-
|
| 226 |
-
# Display the DataFrame using Markdown without the index column
|
| 227 |
-
st.markdown(df.to_markdown(index=False), unsafe_allow_html=True)
|
| 228 |
-
|
| 229 |
-
## ............................................... ##
|
| 230 |
-
# Enhanced title with larger font size and a different color
|
| 231 |
-
title = f"<h1 style='color: red; font-size: 25px; text-align: center; '>{stock_name}'s Stock Technical Analysis</h1>"
|
| 232 |
-
st.markdown(title, unsafe_allow_html=True)
|
| 233 |
-
|
| 234 |
-
with st.expander("See Details"):
|
| 235 |
-
# Describing the data
|
| 236 |
-
st.subheader(f'Data from {start_date} - {end_date}')
|
| 237 |
-
data = yf.download(user_input, start_date, end_date)
|
| 238 |
-
|
| 239 |
-
if data.empty:
|
| 240 |
-
# Display a message to the user when no data is available
|
| 241 |
-
st.warning(f"No data available for stock symbol {stock_name} in the specified date range.")
|
| 242 |
-
else:
|
| 243 |
-
# Reset the index to add the date column
|
| 244 |
-
data = data.reset_index()
|
| 245 |
-
|
| 246 |
-
# Display data in a Plotly table
|
| 247 |
-
fig = go.Figure(data=[go.Table(
|
| 248 |
-
header=dict(values=list(data.columns),
|
| 249 |
-
font=dict(size=12, color='white'),
|
| 250 |
-
fill_color='#264653',
|
| 251 |
-
line_color='rgba(255,255,255,0.2)',
|
| 252 |
-
align=['left', 'center'],
|
| 253 |
-
height=20),
|
| 254 |
-
cells=dict(values=[data[k].tolist() for k in data.columns],
|
| 255 |
-
font=dict(size=12),
|
| 256 |
-
align=['left', 'center'],
|
| 257 |
-
line_color='rgba(255,255,255,0.2)',
|
| 258 |
-
height=20))])
|
| 259 |
-
|
| 260 |
-
fig.update_layout(title_text=f"Data for {stock_name}", title_font_color='#264653', title_x=0, margin=dict(l=0, r=10, b=10, t=30))
|
| 261 |
-
|
| 262 |
-
st.plotly_chart(fig, use_container_width=True)
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
st.markdown(f"<h2 style='text-align: center; color: #264653;'>Data Overview for {stock_name}</h2>", unsafe_allow_html=True)
|
| 266 |
-
# Get the description of the data
|
| 267 |
-
description = data.describe()
|
| 268 |
-
|
| 269 |
-
# Dictionary of columns and rows to highlight
|
| 270 |
-
highlight_dict = {
|
| 271 |
-
"Open": ["mean", "min", "max", "std"],
|
| 272 |
-
"High": ["mean", "min", "max", "std"],
|
| 273 |
-
"Low": ["mean", "min", "max", "std"],
|
| 274 |
-
"Close": ["mean", "min", "max", "std"],
|
| 275 |
-
"Adj Close": ["mean", "min", "max", "std"]
|
| 276 |
-
}
|
| 277 |
-
|
| 278 |
-
# Colors for specific rows
|
| 279 |
-
color_dict = {
|
| 280 |
-
"mean": "lightgreen",
|
| 281 |
-
"min": "salmon",
|
| 282 |
-
"max": "lightblue",
|
| 283 |
-
"std": "lightyellow"
|
| 284 |
-
}
|
| 285 |
-
|
| 286 |
-
# Function to highlight specific columns and rows based on the dictionaries
|
| 287 |
-
def highlight_specific_cells(val, col_name, row_name):
|
| 288 |
-
if col_name in highlight_dict and row_name in highlight_dict[col_name]:
|
| 289 |
-
return f'background-color: {color_dict[row_name]}'
|
| 290 |
-
return ''
|
| 291 |
-
|
| 292 |
-
styled_description = description.style.apply(lambda row: [highlight_specific_cells(val, col, row.name) for col, val in row.items()], axis=1)
|
| 293 |
-
|
| 294 |
-
# Display the styled table in Streamlit
|
| 295 |
-
st.table(styled_description)
|
| 296 |
-
|
| 297 |
-
### ............................................... ##
|
| 298 |
-
# Stock Price Over Time
|
| 299 |
-
g1, g2, g3 = st.columns((1.2,1.2,1))
|
| 300 |
-
|
| 301 |
-
fig1 = px.line(data, x='Date', y='Close', template='seaborn')
|
| 302 |
-
fig1.update_traces(line_color='#264653')
|
| 303 |
-
fig1.update_layout(title_text="Stock Price Over Time", title_x=0, margin=dict(l=20, r=20, b=20, t=30), yaxis_title=None, xaxis_title=None, height=400, width=700)
|
| 304 |
-
g1.plotly_chart(fig1, use_container_width=True)
|
| 305 |
-
|
| 306 |
-
# Volume of Stocks Traded Over Time
|
| 307 |
-
fig2 = px.bar(data, x='Date', y='Volume', template='seaborn')
|
| 308 |
-
fig2.update_traces(marker_color='#7A9E9F')
|
| 309 |
-
fig2.update_layout(title_text="Volume of Stocks Traded Over Time", title_x=0, margin=dict(l=20, r=20, b=20, t=30), yaxis_title=None, xaxis_title=None, height=400, width=700)
|
| 310 |
-
g2.plotly_chart(fig2, use_container_width=True)
|
| 311 |
-
|
| 312 |
-
# Moving Averages
|
| 313 |
-
short_window = 40
|
| 314 |
-
long_window = 100
|
| 315 |
-
data['Short_MA'] = data['Close'].rolling(window=short_window).mean()
|
| 316 |
-
data['Long_MA'] = data['Close'].rolling(window=long_window).mean()
|
| 317 |
-
fig3 = px.line(data, x='Date', y='Close', template='seaborn')
|
| 318 |
-
fig3.add_scatter(x=data['Date'], y=data['Short_MA'], mode='lines', line=dict(color="red"), name=f'Short {short_window}D MA')
|
| 319 |
-
fig3.add_scatter(x=data['Date'], y=data['Long_MA'], mode='lines', line=dict(color="blue"), name=f'Long {long_window}D MA')
|
| 320 |
-
fig3.update_layout(title_text="Stock Price with Moving Averages", title_x=0, margin=dict(l=20, r=20, b=20, t=30), yaxis_title=None, xaxis_title=None, legend=dict(orientation="h", yanchor="bottom", y=0.9, xanchor="right", x=0.99), height=400, width=700)
|
| 321 |
-
g3.plotly_chart(fig3, use_container_width=True)
|
| 322 |
-
|
| 323 |
-
## ............................................... ##
|
| 324 |
-
# Daily Returns
|
| 325 |
-
g4, g5, g6 = st.columns((1,1,1))
|
| 326 |
-
data['Daily_Returns'] = data['Close'].pct_change()
|
| 327 |
-
fig4 = px.line(data, x='Date', y='Daily_Returns', template='seaborn')
|
| 328 |
-
fig4.update_traces(line_color='#E76F51')
|
| 329 |
-
fig4.update_layout(title_text="Daily Returns", title_x=0, margin=dict(l=0, r=10, b=10, t=30), yaxis_title=None, xaxis_title=None)
|
| 330 |
-
g4.plotly_chart(fig4, use_container_width=True)
|
| 331 |
-
|
| 332 |
-
# Cumulative Returns
|
| 333 |
-
data['Cumulative_Returns'] = (1 + data['Daily_Returns']).cumprod()
|
| 334 |
-
fig5 = px.line(data, x='Date', y='Cumulative_Returns', template='seaborn')
|
| 335 |
-
fig5.update_traces(line_color='#2A9D8F')
|
| 336 |
-
fig5.update_layout(title_text="Cumulative Returns", title_x=0, margin=dict(l=0, r=10, b=10, t=30), yaxis_title=None, xaxis_title=None)
|
| 337 |
-
g5.plotly_chart(fig5, use_container_width=True)
|
| 338 |
-
# Stock Price Distribution
|
| 339 |
-
fig6 = px.histogram(data, x='Close', template='seaborn', nbins=50)
|
| 340 |
-
fig6.update_traces(marker_color='#F4A261')
|
| 341 |
-
fig6.update_layout(title_text="Stock Price Distribution", title_x=0, margin=dict(l=0, r=10, b=10, t=30), yaxis_title=None, xaxis_title=None)
|
| 342 |
-
g6.plotly_chart(fig6, use_container_width=True)
|
| 343 |
-
|
| 344 |
-
## ............................................... ##
|
| 345 |
-
|
| 346 |
-
# Bollinger Bands
|
| 347 |
-
g7, g8, g9 = st.columns((1,1,1))
|
| 348 |
-
rolling_mean = data['Close'].rolling(window=20).mean()
|
| 349 |
-
rolling_std = data['Close'].rolling(window=20).std()
|
| 350 |
-
data['Bollinger_Upper'] = rolling_mean + (rolling_std * 2)
|
| 351 |
-
data['Bollinger_Lower'] = rolling_mean - (rolling_std * 2)
|
| 352 |
-
fig7 = px.line(data, x='Date', y='Close', template='seaborn')
|
| 353 |
-
fig7.add_scatter(x=data['Date'], y=data['Bollinger_Upper'], mode='lines', line=dict(color="green"), name='Upper Bollinger Band')
|
| 354 |
-
fig7.add_scatter(x=data['Date'], y=data['Bollinger_Lower'], mode='lines', line=dict(color="red"), name='Lower Bollinger Band')
|
| 355 |
-
fig7.update_layout(title_text="Bollinger Bands", title_x=0, margin=dict(l=0, r=10, b=10, t=30), yaxis_title=None, xaxis_title=None)
|
| 356 |
-
g7.plotly_chart(fig7, use_container_width=True)
|
| 357 |
-
|
| 358 |
-
# Stock Price vs. Volume
|
| 359 |
-
fig8 = px.line(data, x='Date', y='Close', template='seaborn')
|
| 360 |
-
fig8.add_bar(x=data['Date'], y=data['Volume'], name='Volume')
|
| 361 |
-
fig8.update_layout(title_text="Stock Price vs. Volume", title_x=0, margin=dict(l=0, r=10, b=10, t=30), yaxis_title=None, xaxis_title=None)
|
| 362 |
-
g8.plotly_chart(fig8, use_container_width=True)
|
| 363 |
-
|
| 364 |
-
# MACD
|
| 365 |
-
data['12D_EMA'] = data['Close'].ewm(span=12, adjust=False).mean()
|
| 366 |
-
data['26D_EMA'] = data['Close'].ewm(span=26, adjust=False).mean()
|
| 367 |
-
data['MACD'] = data['12D_EMA'] - data['26D_EMA']
|
| 368 |
-
data['Signal_Line'] = data['MACD'].ewm(span=9, adjust=False).mean()
|
| 369 |
-
fig9 = px.line(data, x='Date', y='MACD', template='seaborn', title="MACD")
|
| 370 |
-
fig9.add_scatter(x=data['Date'], y=data['Signal_Line'], mode='lines', line=dict(color="orange"), name='Signal Line')
|
| 371 |
-
fig9.update_layout(title_text="MACD", title_x=0, margin=dict(l=0, r=10, b=10, t=30), yaxis_title=None, xaxis_title=None)
|
| 372 |
-
g9.plotly_chart(fig9, use_container_width=True)
|
| 373 |
-
|
| 374 |
-
### ............................................... ##
|
| 375 |
-
|
| 376 |
-
# Relative Strength Index (RSI)
|
| 377 |
-
g10, g11, g12 = st.columns((1,1,1))
|
| 378 |
-
delta = data['Close'].diff()
|
| 379 |
-
gain = (delta.where(delta > 0, 0)).fillna(0)
|
| 380 |
-
loss = (-delta.where(delta < 0, 0)).fillna(0)
|
| 381 |
-
avg_gain = gain.rolling(window=14).mean()
|
| 382 |
-
avg_loss = loss.rolling(window=14).mean()
|
| 383 |
-
rs = avg_gain / avg_loss
|
| 384 |
-
data['RSI'] = 100 - (100 / (1 + rs))
|
| 385 |
-
fig10 = px.line(data, x='Date', y='RSI', template='seaborn')
|
| 386 |
-
fig10.update_layout(title_text="Relative Strength Index (RSI)", title_x=0, margin=dict(l=0, r=10, b=10, t=30), yaxis_title=None, xaxis_title=None)
|
| 387 |
-
g10.plotly_chart(fig10, use_container_width=True)
|
| 388 |
-
|
| 389 |
-
# Candlestick Chart
|
| 390 |
-
fig11 = go.Figure(data=[go.Candlestick(x=data['Date'],
|
| 391 |
-
open=data['Open'],
|
| 392 |
-
high=data['High'],
|
| 393 |
-
low=data['Low'],
|
| 394 |
-
close=data['Close'])])
|
| 395 |
-
fig11.update_layout(title_text="Candlestick Chart", title_x=0, margin=dict(l=0, r=10, b=10, t=30))
|
| 396 |
-
g11.plotly_chart(fig11, use_container_width=True)
|
| 397 |
-
|
| 398 |
-
# Correlation Matrix
|
| 399 |
-
corr_matrix = data[['Open', 'High', 'Low', 'Close', 'Volume']].corr()
|
| 400 |
-
fig12 = px.imshow(corr_matrix, template='seaborn')
|
| 401 |
-
fig12.update_layout(title_text="Correlation Matrix", title_x=0, margin=dict(l=0, r=10, b=10, t=30))
|
| 402 |
-
g12.plotly_chart(fig12, use_container_width=True)
|
| 403 |
-
|
| 404 |
-
### ............................................... ##
|
| 405 |
-
# Price Rate of Change (ROC)
|
| 406 |
-
g13, g14, g15 = st.columns((1,1,1))
|
| 407 |
-
n = 12
|
| 408 |
-
data['ROC'] = ((data['Close'] - data['Close'].shift(n)) / data['Close'].shift(n)) * 100
|
| 409 |
-
fig13 = px.line(data, x='Date', y='ROC', template='seaborn')
|
| 410 |
-
fig13.update_layout(title_text="Price Rate of Change (ROC)", title_x=0, margin=dict(l=0, r=10, b=10, t=30), yaxis_title=None, xaxis_title=None)
|
| 411 |
-
g13.plotly_chart(fig13, use_container_width=True)
|
| 412 |
-
|
| 413 |
-
# Stochastic Oscillator
|
| 414 |
-
low_min = data['Low'].rolling(window=14).min()
|
| 415 |
-
high_max = data['High'].rolling(window=14).max()
|
| 416 |
-
data['%K'] = (100 * (data['Close'] - low_min) / (high_max - low_min))
|
| 417 |
-
data['%D'] = data['%K'].rolling(window=3).mean()
|
| 418 |
-
fig14 = px.line(data, x='Date', y='%K', template='seaborn')
|
| 419 |
-
fig14.add_scatter(x=data['Date'], y=data['%D'], mode='lines', line=dict(color="orange"), name='%D (3-day SMA of %K)')
|
| 420 |
-
fig14.update_layout(title_text="Stochastic Oscillator", title_x=0, margin=dict(l=0, r=10, b=10, t=30), yaxis_title=None, xaxis_title=None)
|
| 421 |
-
g14.plotly_chart(fig14, use_container_width=True)
|
| 422 |
-
|
| 423 |
-
# Historical Volatility
|
| 424 |
-
data['Log_Return'] = np.log(data['Close'] / data['Close'].shift(1))
|
| 425 |
-
data['Historical_Volatility'] = data['Log_Return'].rolling(window=252).std() * np.sqrt(252)
|
| 426 |
-
fig15 = px.line(data, x='Date', y='Historical_Volatility', template='seaborn')
|
| 427 |
-
fig15.update_layout(title_text="Historical Volatility (252-day)", title_x=0, margin=dict(l=0, r=10, b=10, t=30), yaxis_title=None, xaxis_title=None)
|
| 428 |
-
g15.plotly_chart(fig15, use_container_width=True)
|
| 429 |
-
|
| 430 |
-
### ............................................... ##
|
| 431 |
-
|
| 432 |
-
# Visualizing the data and want to get the data when hovering over the graph
|
| 433 |
-
st.subheader('Closing Price vs Time Chart')
|
| 434 |
-
fig1 = go.Figure()
|
| 435 |
-
fig1.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Close'))
|
| 436 |
-
fig1.layout.update(hovermode='x')
|
| 437 |
-
# Display the figure in Streamlit
|
| 438 |
-
st.plotly_chart(fig1,use_container_width=True)
|
| 439 |
-
|
| 440 |
-
st.subheader('Closing Price vs Time Chart with 100MA')
|
| 441 |
-
ma100 = data['Close'].rolling(100).mean()
|
| 442 |
-
fig2 = go.Figure()
|
| 443 |
-
# Add traces for 100MA and Closing Price
|
| 444 |
-
fig2.add_trace(go.Scatter(x=data.index, y=ma100, mode='lines', name='100MA'))
|
| 445 |
-
fig2.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Closing Price'))
|
| 446 |
-
fig2.layout.update(hovermode='x')
|
| 447 |
-
# Display the figure in Streamlit
|
| 448 |
-
st.plotly_chart(fig2,use_container_width=True)
|
| 449 |
-
|
| 450 |
-
st.subheader('Closing Price vs Time Chart with 100MA and 200MA')
|
| 451 |
-
ma100 = data['Close'].rolling(100).mean()
|
| 452 |
-
ma200 = data['Close'].rolling(200).mean()
|
| 453 |
-
fig3 = go.Figure()
|
| 454 |
-
# Add traces for 100MA and Closing Price
|
| 455 |
-
fig3.add_trace(go.Scatter(x=data.index, y=ma100, mode='lines', name='100MA'))
|
| 456 |
-
fig3.add_trace(go.Scatter(x=data.index, y=ma200, mode='lines', name='200MA'))
|
| 457 |
-
fig3.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Closing Price'))
|
| 458 |
-
fig3.layout.update(hovermode='x')
|
| 459 |
-
|
| 460 |
-
# Display the figure in Streamlit
|
| 461 |
-
st.plotly_chart(fig3,use_container_width=True)
|
| 462 |
-
|
| 463 |
-
## ............................................... ##
|
| 464 |
-
# Enhanced title with larger font size and a different color
|
| 465 |
-
title = f"<h1 style='color: red; font-size: 25px; text-align: center; '>{stock_name}'s Stock Prediction</h1>"
|
| 466 |
-
st.markdown(title, unsafe_allow_html=True)
|
| 467 |
-
|
| 468 |
-
with st.expander("See Details"):
|
| 469 |
-
# Define the minimum number of days required for predictions
|
| 470 |
-
minimum_days_for_predictions = 100
|
| 471 |
-
|
| 472 |
-
# Check if the available data is less than the minimum required days
|
| 473 |
-
if len(data) < minimum_days_for_predictions:
|
| 474 |
-
st.warning(f"The available data for {stock_name} is less than {minimum_days_for_predictions} days, which is insufficient for predictions.")
|
| 475 |
-
else:
|
| 476 |
-
# Splitting the data into training and testing data
|
| 477 |
-
data_training = pd.DataFrame(data['Close'][0:int(len(data)*0.70)])
|
| 478 |
-
data_testing = pd.DataFrame(data['Close'][int(len(data)*0.70): int(len(data))])
|
| 479 |
-
|
| 480 |
-
# Scaling the data
|
| 481 |
-
scaler = MinMaxScaler(feature_range=(0,1))
|
| 482 |
-
data_training_array = scaler.fit_transform(data_training)
|
| 483 |
-
|
| 484 |
-
# load the model
|
| 485 |
-
model = load_model('best_model_MAPI.h5')
|
| 486 |
-
|
| 487 |
-
# Testing the model
|
| 488 |
-
past_100_days = data_training.tail(100)
|
| 489 |
-
final_df = pd.concat([past_100_days,data_testing], ignore_index=True)
|
| 490 |
-
input_data = scaler.fit_transform(final_df)
|
| 491 |
-
|
| 492 |
-
x_test = []
|
| 493 |
-
y_test = []
|
| 494 |
-
for i in range(100, input_data.shape[0]):
|
| 495 |
-
x_test.append(input_data[i-100:i])
|
| 496 |
-
y_test.append(input_data[i,0])
|
| 497 |
-
|
| 498 |
-
x_test, y_test = np.array(x_test), np.array(y_test)
|
| 499 |
-
|
| 500 |
-
y_predicted = model.predict(x_test)
|
| 501 |
-
|
| 502 |
-
scaler = scaler.scale_
|
| 503 |
-
scale_factor = 1/scaler[0]
|
| 504 |
-
y_predicted = y_predicted * scale_factor
|
| 505 |
-
y_test = y_test * scale_factor
|
| 506 |
|
| 507 |
-
# Visualizing the results
|
| 508 |
-
st.subheader('Predictions vs Actual')
|
| 509 |
-
fig4 = go.Figure()
|
| 510 |
-
# Add traces for Actual and Predicted Price
|
| 511 |
-
fig4.add_trace(go.Scatter(x=data.index[-len(y_test):], y=y_test, mode='lines', name='Actual Price'))
|
| 512 |
-
fig4.add_trace(go.Scatter(x=data.index[-len(y_predicted):], y=y_predicted[:,0], mode='lines', name='Predicted Price'))
|
| 513 |
-
fig4.layout.update(hovermode='x')
|
| 514 |
-
# Display the figure in Streamlit
|
| 515 |
-
st.plotly_chart(fig4,use_container_width=True)
|
| 516 |
|
| 517 |
-
|
| 518 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from pathlib import Path
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
import streamlit as st
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
|
| 5 |
+
st.set_page_config(page_title='Regression Stocks Prediction', layout='wide', page_icon='π')
|
| 6 |
+
st.title("π Stock Analysis and Prediction")
|
| 7 |
+
st.write(
|
| 8 |
+
"""
|
| 9 |
+
Welcome to the **π Stock Analysis and Prediction**!
|
| 10 |
+
"""
|
| 11 |
+
)
|
pages/π_Stock_Analysis.py
ADDED
|
@@ -0,0 +1,516 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pandas as pd
|
| 2 |
+
import numpy as np
|
| 3 |
+
import matplotlib.pyplot as plt
|
| 4 |
+
import pandas_datareader.data as web
|
| 5 |
+
import datetime as dt
|
| 6 |
+
import yfinance as yf
|
| 7 |
+
from sklearn.preprocessing import MinMaxScaler
|
| 8 |
+
from keras.models import load_model
|
| 9 |
+
import streamlit as st
|
| 10 |
+
import plotly.graph_objects as go
|
| 11 |
+
import base64
|
| 12 |
+
import plotly.express as px
|
| 13 |
+
from datetime import datetime
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
## ............................................... ##
|
| 17 |
+
# Set page configuration (Call this once and make changes as needed)
|
| 18 |
+
st.set_page_config(page_title='Regression Stocks Prediction', layout='wide', page_icon=':rocket:')
|
| 19 |
+
|
| 20 |
+
## ............................................... ##
|
| 21 |
+
# Add a dictonary of stock tickers and their company names and make a drop down menu to select the stock to predict
|
| 22 |
+
stock_tickers = {
|
| 23 |
+
"MAPI":"MAPI.JK","MAP Aktif": "MAPA.JK","MAP Boga": "MAPB.JK",
|
| 24 |
+
"Tesla": "TSLA", "Apple": "AAPL", "Microsoft": "MSFT", "Google": "GOOGL",
|
| 25 |
+
"Meta": "META", "Amazon": "AMZN", "Netflix": "NFLX", "Alphabet": "GOOG",
|
| 26 |
+
"Nvidia": "NVDA", "Paypal": "PYPL", "Adobe": "ADBE", "Intel": "INTC",
|
| 27 |
+
"Cisco": "CSCO", "Comcast": "CMCSA", "Pepsi": "PEP", "Costco": "COST",
|
| 28 |
+
"Starbucks": "SBUX", "Walmart": "WMT", "Disney": "DIS", "Visa": "V",
|
| 29 |
+
"Mastercard": "MA", "Boeing": "BA", "IBM": "IBM", "McDonalds": "MCD",
|
| 30 |
+
"Nike": "NKE", "Exxon": "XOM", "Chevron": "CVX", "Verizon": "VZ",
|
| 31 |
+
"AT&T": "T", "Home Depot": "HD", "Salesforce": "CRM", "Oracle": "ORCL",
|
| 32 |
+
"Qualcomm": "QCOM", "AMD": "AMD"
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
st.sidebar.title("Stock Option")
|
| 36 |
+
# Custom CSS to change the sidebar color
|
| 37 |
+
sidebar_css = """
|
| 38 |
+
<style>
|
| 39 |
+
div[data-testid="stSidebar"] > div:first-child {
|
| 40 |
+
width: 350px; # Adjust the width as needed
|
| 41 |
+
background-color: #FF6969;
|
| 42 |
+
}
|
| 43 |
+
</style>
|
| 44 |
+
"""
|
| 45 |
+
|
| 46 |
+
# User Input
|
| 47 |
+
#default_index = stock_tickers.keys().index("MAPI.JK") if "MAPI.JK" in stock_tickers.keys() else 0
|
| 48 |
+
#st.markdown(sidebar_css, unsafe_allow_html=True)
|
| 49 |
+
#user_input = st.sidebar.selectbox("Select a Stock", list(stock_tickers.keys()), index=default_index , key="main_selectbox")
|
| 50 |
+
#stock_name = user_input
|
| 51 |
+
#user_input = stock_tickers[user_input]
|
| 52 |
+
|
| 53 |
+
user_input = st.sidebar.text_input("Select a Stock", "MAPI.JK")
|
| 54 |
+
|
| 55 |
+
# User input for start and end dates using calendar widget
|
| 56 |
+
start_date = st.sidebar.date_input("Select start date:", datetime(2023, 1, 1))
|
| 57 |
+
end_date = st.sidebar.date_input("Select end date:", datetime(2023, 12, 1))
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
st.sidebar.markdown("----")
|
| 61 |
+
st.sidebar.markdown("Β© 2023 Stocks Prediction App")
|
| 62 |
+
st.sidebar.markdown("----")
|
| 63 |
+
st.sidebar.markdown("Example Stock Tickers")
|
| 64 |
+
st.sidebar.markdown(stock_tickers)
|
| 65 |
+
|
| 66 |
+
## ............................................... ##
|
| 67 |
+
# Page Title and Description
|
| 68 |
+
st.title("Stock Price Analysis and Prediction")
|
| 69 |
+
st.write("Created by Bayhaqy")
|
| 70 |
+
st.write("Using Dataset MAPI to Train and Test the Model")
|
| 71 |
+
|
| 72 |
+
## ............................................... ##
|
| 73 |
+
|
| 74 |
+
# Try to fetch information from Yahoo Finance
|
| 75 |
+
try:
|
| 76 |
+
stock_info = yf.Ticker(user_input).info
|
| 77 |
+
|
| 78 |
+
# Check if the 'longName' key exists in stock_info
|
| 79 |
+
if 'longName' in stock_info:
|
| 80 |
+
stock_name = stock_info['longName']
|
| 81 |
+
else:
|
| 82 |
+
stock_name = user_input
|
| 83 |
+
|
| 84 |
+
# Fetch the latest news using yfinance
|
| 85 |
+
news_data = yf.Ticker(user_input).news
|
| 86 |
+
|
| 87 |
+
# Create a Streamlit app
|
| 88 |
+
title = f"<h1 style='color: red; font-size: 25px; text-align: center; '>{stock_name}'s Stock Fundamental Analysis</h1>"
|
| 89 |
+
st.markdown(title, unsafe_allow_html=True)
|
| 90 |
+
|
| 91 |
+
with st.expander("See Details"):
|
| 92 |
+
## ............................................... ##
|
| 93 |
+
# Display the retrieved stock information
|
| 94 |
+
if 'longName' in stock_info:
|
| 95 |
+
company_name = stock_info['longName']
|
| 96 |
+
st.write(f"Company Name: {company_name}")
|
| 97 |
+
else:
|
| 98 |
+
st.write("Company name information not available for this stock.")
|
| 99 |
+
|
| 100 |
+
if 'industry' in stock_info:
|
| 101 |
+
Industry = stock_info['industry']
|
| 102 |
+
st.write(f"Industry: {Industry}")
|
| 103 |
+
else:
|
| 104 |
+
st.write("Industry information not available for this stock.")
|
| 105 |
+
|
| 106 |
+
if 'sector' in stock_info:
|
| 107 |
+
Sector = stock_info['sector']
|
| 108 |
+
st.write(f"Sector: {Sector}")
|
| 109 |
+
else:
|
| 110 |
+
st.write("Sector information not available for this stock.")
|
| 111 |
+
|
| 112 |
+
if 'website' in stock_info:
|
| 113 |
+
Website = stock_info['website']
|
| 114 |
+
st.write(f"Sector: {Website}")
|
| 115 |
+
else:
|
| 116 |
+
st.write("Website information not available for this stock.")
|
| 117 |
+
|
| 118 |
+
if 'marketCap' in stock_info:
|
| 119 |
+
MarketCap = stock_info['marketCap']
|
| 120 |
+
st.write(f"Market Cap: {MarketCap}")
|
| 121 |
+
else:
|
| 122 |
+
st.write("Market Cap information not available for this stock.")
|
| 123 |
+
|
| 124 |
+
if 'previousClose' in stock_info:
|
| 125 |
+
PreviousClose = stock_info['previousClose']
|
| 126 |
+
st.write(f"Previous Close: {PreviousClose}")
|
| 127 |
+
else:
|
| 128 |
+
st.write("Previous Close information not available for this stock.")
|
| 129 |
+
|
| 130 |
+
if 'dividendYield' in stock_info:
|
| 131 |
+
dividend_yield = stock_info['dividendYield'] * 100 # Convert to percentage
|
| 132 |
+
st.write(f"Dividend Yield: {dividend_yield:.2f}%")
|
| 133 |
+
else:
|
| 134 |
+
st.write("Dividend Yield information not available for this stock.")
|
| 135 |
+
|
| 136 |
+
## ............................................... ##
|
| 137 |
+
# Display financial metrics
|
| 138 |
+
st.subheader('Financial Metrics')
|
| 139 |
+
if 'trailingEps' in stock_info:
|
| 140 |
+
trailing_eps = stock_info['trailingEps']
|
| 141 |
+
st.write(f"Earnings Per Share (EPS): {trailing_eps:.2f}")
|
| 142 |
+
else:
|
| 143 |
+
st.write("Earnings Per Share (EPS) information not available for this stock.")
|
| 144 |
+
|
| 145 |
+
if 'trailingPE' in stock_info:
|
| 146 |
+
trailing_pe = stock_info['trailingPE']
|
| 147 |
+
st.write(f"Price-to-Earnings (P/E) Ratio: {trailing_pe:.2f}")
|
| 148 |
+
else:
|
| 149 |
+
st.write("Price-to-Earnings (P/E) Ratio information not available for this stock.")
|
| 150 |
+
|
| 151 |
+
if 'priceToSalesTrailing12Months' in stock_info:
|
| 152 |
+
priceToSalesTrailing_12Months = stock_info['priceToSalesTrailing12Months']
|
| 153 |
+
st.write(f"Price-to-Sales (P/S) Ratio: {priceToSalesTrailing_12Months:.2f}")
|
| 154 |
+
else:
|
| 155 |
+
st.write("Price-to-Sales (P/S) Ratio information not available for this stock.")
|
| 156 |
+
|
| 157 |
+
if 'priceToBook' in stock_info:
|
| 158 |
+
price_ToBook = stock_info['priceToBook']
|
| 159 |
+
st.write(f"Price-to-Book (P/B) Ratio: {price_ToBook:.2f}")
|
| 160 |
+
else:
|
| 161 |
+
st.write("Price-to-Book (P/B) Ratio information not available for this stock.")
|
| 162 |
+
|
| 163 |
+
## ............................................... ##
|
| 164 |
+
# Display more detailed information
|
| 165 |
+
st.subheader('Company Summary')
|
| 166 |
+
if 'longBusinessSummary' in stock_info:
|
| 167 |
+
LongBusinessSummary = stock_info['longBusinessSummary']
|
| 168 |
+
st.write(f"Company Summary: {LongBusinessSummary}")
|
| 169 |
+
else:
|
| 170 |
+
st.write("Company Summary information not available for this stock.")
|
| 171 |
+
|
| 172 |
+
## ............................................... ##
|
| 173 |
+
# Display information about company officers
|
| 174 |
+
st.subheader('Company Officers')
|
| 175 |
+
if 'fullTimeEmployees' in stock_info:
|
| 176 |
+
FullTimeEmployees = stock_info['fullTimeEmployees']
|
| 177 |
+
st.write(f"Full Time Employees: {FullTimeEmployees}")
|
| 178 |
+
else:
|
| 179 |
+
st.write("Full Time Employees information not available for this stock.")
|
| 180 |
+
|
| 181 |
+
if 'companyOfficers' in stock_info:
|
| 182 |
+
officers = stock_info['companyOfficers']
|
| 183 |
+
officer_data = []
|
| 184 |
+
|
| 185 |
+
# Create a DataFrame
|
| 186 |
+
df = pd.DataFrame(columns=["Name", "Title", "Age"])
|
| 187 |
+
|
| 188 |
+
# Populate the DataFrame with officer information
|
| 189 |
+
#for officer in officers:
|
| 190 |
+
# officer_data.append([officer['name'], officer['title'], officer['age']])
|
| 191 |
+
|
| 192 |
+
for officer in officers:
|
| 193 |
+
name = officer.get('name', 'N/A')
|
| 194 |
+
title = officer.get('title', 'N/A')
|
| 195 |
+
age = officer.get('age', 'N/A')
|
| 196 |
+
officer_data.append([name, title, age])
|
| 197 |
+
|
| 198 |
+
|
| 199 |
+
df = pd.concat([df, pd.DataFrame(officer_data, columns=["Name", "Title", "Age"])], ignore_index=True)
|
| 200 |
+
|
| 201 |
+
# Display the DataFrame using Markdown without the index column
|
| 202 |
+
st.markdown(df.to_markdown(index=False))
|
| 203 |
+
|
| 204 |
+
else:
|
| 205 |
+
st.write("Company Officers information not available for this stock.")
|
| 206 |
+
|
| 207 |
+
## ............................................... ##
|
| 208 |
+
# Display the latest news
|
| 209 |
+
st.subheader('Latest News')
|
| 210 |
+
|
| 211 |
+
# Prepare the data for the DataFrame
|
| 212 |
+
news_data_for_dataframe = []
|
| 213 |
+
for news_item in news_data:
|
| 214 |
+
news_title = news_item['title']
|
| 215 |
+
news_link = f"[Link]({news_item['link']})"
|
| 216 |
+
news_publisher = news_item['publisher']
|
| 217 |
+
news_provider_publish_time = pd.to_datetime(news_item['providerPublishTime'], unit='s')
|
| 218 |
+
news_type = news_item['type']
|
| 219 |
+
news_data_for_dataframe.append([news_title, news_link, news_publisher, news_provider_publish_time, news_type])
|
| 220 |
+
|
| 221 |
+
# Create a Pandas DataFrame
|
| 222 |
+
df = pd.DataFrame(news_data_for_dataframe, columns=["Title", "Link", "Publisher", "Provider Publish Time", "Type"])
|
| 223 |
+
|
| 224 |
+
# Display the DataFrame using Markdown without the index column
|
| 225 |
+
st.markdown(df.to_markdown(index=False), unsafe_allow_html=True)
|
| 226 |
+
|
| 227 |
+
## ............................................... ##
|
| 228 |
+
# Enhanced title with larger font size and a different color
|
| 229 |
+
title = f"<h1 style='color: red; font-size: 25px; text-align: center; '>{stock_name}'s Stock Technical Analysis</h1>"
|
| 230 |
+
st.markdown(title, unsafe_allow_html=True)
|
| 231 |
+
|
| 232 |
+
with st.expander("See Details"):
|
| 233 |
+
# Describing the data
|
| 234 |
+
st.subheader(f'Data from {start_date} - {end_date}')
|
| 235 |
+
data = yf.download(user_input, start_date, end_date)
|
| 236 |
+
|
| 237 |
+
if data.empty:
|
| 238 |
+
# Display a message to the user when no data is available
|
| 239 |
+
st.warning(f"No data available for stock symbol {stock_name} in the specified date range.")
|
| 240 |
+
else:
|
| 241 |
+
# Reset the index to add the date column
|
| 242 |
+
data = data.reset_index()
|
| 243 |
+
|
| 244 |
+
# Display data in a Plotly table
|
| 245 |
+
fig = go.Figure(data=[go.Table(
|
| 246 |
+
header=dict(values=list(data.columns),
|
| 247 |
+
font=dict(size=12, color='white'),
|
| 248 |
+
fill_color='#264653',
|
| 249 |
+
line_color='rgba(255,255,255,0.2)',
|
| 250 |
+
align=['left', 'center'],
|
| 251 |
+
height=20),
|
| 252 |
+
cells=dict(values=[data[k].tolist() for k in data.columns],
|
| 253 |
+
font=dict(size=12),
|
| 254 |
+
align=['left', 'center'],
|
| 255 |
+
line_color='rgba(255,255,255,0.2)',
|
| 256 |
+
height=20))])
|
| 257 |
+
|
| 258 |
+
fig.update_layout(title_text=f"Data for {stock_name}", title_font_color='#264653', title_x=0, margin=dict(l=0, r=10, b=10, t=30))
|
| 259 |
+
|
| 260 |
+
st.plotly_chart(fig, use_container_width=True)
|
| 261 |
+
|
| 262 |
+
|
| 263 |
+
st.markdown(f"<h2 style='text-align: center; color: #264653;'>Data Overview for {stock_name}</h2>", unsafe_allow_html=True)
|
| 264 |
+
# Get the description of the data
|
| 265 |
+
description = data.describe()
|
| 266 |
+
|
| 267 |
+
# Dictionary of columns and rows to highlight
|
| 268 |
+
highlight_dict = {
|
| 269 |
+
"Open": ["mean", "min", "max", "std"],
|
| 270 |
+
"High": ["mean", "min", "max", "std"],
|
| 271 |
+
"Low": ["mean", "min", "max", "std"],
|
| 272 |
+
"Close": ["mean", "min", "max", "std"],
|
| 273 |
+
"Adj Close": ["mean", "min", "max", "std"]
|
| 274 |
+
}
|
| 275 |
+
|
| 276 |
+
# Colors for specific rows
|
| 277 |
+
color_dict = {
|
| 278 |
+
"mean": "lightgreen",
|
| 279 |
+
"min": "salmon",
|
| 280 |
+
"max": "lightblue",
|
| 281 |
+
"std": "lightyellow"
|
| 282 |
+
}
|
| 283 |
+
|
| 284 |
+
# Function to highlight specific columns and rows based on the dictionaries
|
| 285 |
+
def highlight_specific_cells(val, col_name, row_name):
|
| 286 |
+
if col_name in highlight_dict and row_name in highlight_dict[col_name]:
|
| 287 |
+
return f'background-color: {color_dict[row_name]}'
|
| 288 |
+
return ''
|
| 289 |
+
|
| 290 |
+
styled_description = description.style.apply(lambda row: [highlight_specific_cells(val, col, row.name) for col, val in row.items()], axis=1)
|
| 291 |
+
|
| 292 |
+
# Display the styled table in Streamlit
|
| 293 |
+
st.table(styled_description)
|
| 294 |
+
|
| 295 |
+
### ............................................... ##
|
| 296 |
+
# Stock Price Over Time
|
| 297 |
+
g1, g2, g3 = st.columns((1.2,1.2,1))
|
| 298 |
+
|
| 299 |
+
fig1 = px.line(data, x='Date', y='Close', template='seaborn')
|
| 300 |
+
fig1.update_traces(line_color='#264653')
|
| 301 |
+
fig1.update_layout(title_text="Stock Price Over Time", title_x=0, margin=dict(l=20, r=20, b=20, t=30), yaxis_title=None, xaxis_title=None, height=400, width=700)
|
| 302 |
+
g1.plotly_chart(fig1, use_container_width=True)
|
| 303 |
+
|
| 304 |
+
# Volume of Stocks Traded Over Time
|
| 305 |
+
fig2 = px.bar(data, x='Date', y='Volume', template='seaborn')
|
| 306 |
+
fig2.update_traces(marker_color='#7A9E9F')
|
| 307 |
+
fig2.update_layout(title_text="Volume of Stocks Traded Over Time", title_x=0, margin=dict(l=20, r=20, b=20, t=30), yaxis_title=None, xaxis_title=None, height=400, width=700)
|
| 308 |
+
g2.plotly_chart(fig2, use_container_width=True)
|
| 309 |
+
|
| 310 |
+
# Moving Averages
|
| 311 |
+
short_window = 40
|
| 312 |
+
long_window = 100
|
| 313 |
+
data['Short_MA'] = data['Close'].rolling(window=short_window).mean()
|
| 314 |
+
data['Long_MA'] = data['Close'].rolling(window=long_window).mean()
|
| 315 |
+
fig3 = px.line(data, x='Date', y='Close', template='seaborn')
|
| 316 |
+
fig3.add_scatter(x=data['Date'], y=data['Short_MA'], mode='lines', line=dict(color="red"), name=f'Short {short_window}D MA')
|
| 317 |
+
fig3.add_scatter(x=data['Date'], y=data['Long_MA'], mode='lines', line=dict(color="blue"), name=f'Long {long_window}D MA')
|
| 318 |
+
fig3.update_layout(title_text="Stock Price with Moving Averages", title_x=0, margin=dict(l=20, r=20, b=20, t=30), yaxis_title=None, xaxis_title=None, legend=dict(orientation="h", yanchor="bottom", y=0.9, xanchor="right", x=0.99), height=400, width=700)
|
| 319 |
+
g3.plotly_chart(fig3, use_container_width=True)
|
| 320 |
+
|
| 321 |
+
## ............................................... ##
|
| 322 |
+
# Daily Returns
|
| 323 |
+
g4, g5, g6 = st.columns((1,1,1))
|
| 324 |
+
data['Daily_Returns'] = data['Close'].pct_change()
|
| 325 |
+
fig4 = px.line(data, x='Date', y='Daily_Returns', template='seaborn')
|
| 326 |
+
fig4.update_traces(line_color='#E76F51')
|
| 327 |
+
fig4.update_layout(title_text="Daily Returns", title_x=0, margin=dict(l=0, r=10, b=10, t=30), yaxis_title=None, xaxis_title=None)
|
| 328 |
+
g4.plotly_chart(fig4, use_container_width=True)
|
| 329 |
+
|
| 330 |
+
# Cumulative Returns
|
| 331 |
+
data['Cumulative_Returns'] = (1 + data['Daily_Returns']).cumprod()
|
| 332 |
+
fig5 = px.line(data, x='Date', y='Cumulative_Returns', template='seaborn')
|
| 333 |
+
fig5.update_traces(line_color='#2A9D8F')
|
| 334 |
+
fig5.update_layout(title_text="Cumulative Returns", title_x=0, margin=dict(l=0, r=10, b=10, t=30), yaxis_title=None, xaxis_title=None)
|
| 335 |
+
g5.plotly_chart(fig5, use_container_width=True)
|
| 336 |
+
# Stock Price Distribution
|
| 337 |
+
fig6 = px.histogram(data, x='Close', template='seaborn', nbins=50)
|
| 338 |
+
fig6.update_traces(marker_color='#F4A261')
|
| 339 |
+
fig6.update_layout(title_text="Stock Price Distribution", title_x=0, margin=dict(l=0, r=10, b=10, t=30), yaxis_title=None, xaxis_title=None)
|
| 340 |
+
g6.plotly_chart(fig6, use_container_width=True)
|
| 341 |
+
|
| 342 |
+
## ............................................... ##
|
| 343 |
+
|
| 344 |
+
# Bollinger Bands
|
| 345 |
+
g7, g8, g9 = st.columns((1,1,1))
|
| 346 |
+
rolling_mean = data['Close'].rolling(window=20).mean()
|
| 347 |
+
rolling_std = data['Close'].rolling(window=20).std()
|
| 348 |
+
data['Bollinger_Upper'] = rolling_mean + (rolling_std * 2)
|
| 349 |
+
data['Bollinger_Lower'] = rolling_mean - (rolling_std * 2)
|
| 350 |
+
fig7 = px.line(data, x='Date', y='Close', template='seaborn')
|
| 351 |
+
fig7.add_scatter(x=data['Date'], y=data['Bollinger_Upper'], mode='lines', line=dict(color="green"), name='Upper Bollinger Band')
|
| 352 |
+
fig7.add_scatter(x=data['Date'], y=data['Bollinger_Lower'], mode='lines', line=dict(color="red"), name='Lower Bollinger Band')
|
| 353 |
+
fig7.update_layout(title_text="Bollinger Bands", title_x=0, margin=dict(l=0, r=10, b=10, t=30), yaxis_title=None, xaxis_title=None)
|
| 354 |
+
g7.plotly_chart(fig7, use_container_width=True)
|
| 355 |
+
|
| 356 |
+
# Stock Price vs. Volume
|
| 357 |
+
fig8 = px.line(data, x='Date', y='Close', template='seaborn')
|
| 358 |
+
fig8.add_bar(x=data['Date'], y=data['Volume'], name='Volume')
|
| 359 |
+
fig8.update_layout(title_text="Stock Price vs. Volume", title_x=0, margin=dict(l=0, r=10, b=10, t=30), yaxis_title=None, xaxis_title=None)
|
| 360 |
+
g8.plotly_chart(fig8, use_container_width=True)
|
| 361 |
+
|
| 362 |
+
# MACD
|
| 363 |
+
data['12D_EMA'] = data['Close'].ewm(span=12, adjust=False).mean()
|
| 364 |
+
data['26D_EMA'] = data['Close'].ewm(span=26, adjust=False).mean()
|
| 365 |
+
data['MACD'] = data['12D_EMA'] - data['26D_EMA']
|
| 366 |
+
data['Signal_Line'] = data['MACD'].ewm(span=9, adjust=False).mean()
|
| 367 |
+
fig9 = px.line(data, x='Date', y='MACD', template='seaborn', title="MACD")
|
| 368 |
+
fig9.add_scatter(x=data['Date'], y=data['Signal_Line'], mode='lines', line=dict(color="orange"), name='Signal Line')
|
| 369 |
+
fig9.update_layout(title_text="MACD", title_x=0, margin=dict(l=0, r=10, b=10, t=30), yaxis_title=None, xaxis_title=None)
|
| 370 |
+
g9.plotly_chart(fig9, use_container_width=True)
|
| 371 |
+
|
| 372 |
+
### ............................................... ##
|
| 373 |
+
|
| 374 |
+
# Relative Strength Index (RSI)
|
| 375 |
+
g10, g11, g12 = st.columns((1,1,1))
|
| 376 |
+
delta = data['Close'].diff()
|
| 377 |
+
gain = (delta.where(delta > 0, 0)).fillna(0)
|
| 378 |
+
loss = (-delta.where(delta < 0, 0)).fillna(0)
|
| 379 |
+
avg_gain = gain.rolling(window=14).mean()
|
| 380 |
+
avg_loss = loss.rolling(window=14).mean()
|
| 381 |
+
rs = avg_gain / avg_loss
|
| 382 |
+
data['RSI'] = 100 - (100 / (1 + rs))
|
| 383 |
+
fig10 = px.line(data, x='Date', y='RSI', template='seaborn')
|
| 384 |
+
fig10.update_layout(title_text="Relative Strength Index (RSI)", title_x=0, margin=dict(l=0, r=10, b=10, t=30), yaxis_title=None, xaxis_title=None)
|
| 385 |
+
g10.plotly_chart(fig10, use_container_width=True)
|
| 386 |
+
|
| 387 |
+
# Candlestick Chart
|
| 388 |
+
fig11 = go.Figure(data=[go.Candlestick(x=data['Date'],
|
| 389 |
+
open=data['Open'],
|
| 390 |
+
high=data['High'],
|
| 391 |
+
low=data['Low'],
|
| 392 |
+
close=data['Close'])])
|
| 393 |
+
fig11.update_layout(title_text="Candlestick Chart", title_x=0, margin=dict(l=0, r=10, b=10, t=30))
|
| 394 |
+
g11.plotly_chart(fig11, use_container_width=True)
|
| 395 |
+
|
| 396 |
+
# Correlation Matrix
|
| 397 |
+
corr_matrix = data[['Open', 'High', 'Low', 'Close', 'Volume']].corr()
|
| 398 |
+
fig12 = px.imshow(corr_matrix, template='seaborn')
|
| 399 |
+
fig12.update_layout(title_text="Correlation Matrix", title_x=0, margin=dict(l=0, r=10, b=10, t=30))
|
| 400 |
+
g12.plotly_chart(fig12, use_container_width=True)
|
| 401 |
+
|
| 402 |
+
### ............................................... ##
|
| 403 |
+
# Price Rate of Change (ROC)
|
| 404 |
+
g13, g14, g15 = st.columns((1,1,1))
|
| 405 |
+
n = 12
|
| 406 |
+
data['ROC'] = ((data['Close'] - data['Close'].shift(n)) / data['Close'].shift(n)) * 100
|
| 407 |
+
fig13 = px.line(data, x='Date', y='ROC', template='seaborn')
|
| 408 |
+
fig13.update_layout(title_text="Price Rate of Change (ROC)", title_x=0, margin=dict(l=0, r=10, b=10, t=30), yaxis_title=None, xaxis_title=None)
|
| 409 |
+
g13.plotly_chart(fig13, use_container_width=True)
|
| 410 |
+
|
| 411 |
+
# Stochastic Oscillator
|
| 412 |
+
low_min = data['Low'].rolling(window=14).min()
|
| 413 |
+
high_max = data['High'].rolling(window=14).max()
|
| 414 |
+
data['%K'] = (100 * (data['Close'] - low_min) / (high_max - low_min))
|
| 415 |
+
data['%D'] = data['%K'].rolling(window=3).mean()
|
| 416 |
+
fig14 = px.line(data, x='Date', y='%K', template='seaborn')
|
| 417 |
+
fig14.add_scatter(x=data['Date'], y=data['%D'], mode='lines', line=dict(color="orange"), name='%D (3-day SMA of %K)')
|
| 418 |
+
fig14.update_layout(title_text="Stochastic Oscillator", title_x=0, margin=dict(l=0, r=10, b=10, t=30), yaxis_title=None, xaxis_title=None)
|
| 419 |
+
g14.plotly_chart(fig14, use_container_width=True)
|
| 420 |
+
|
| 421 |
+
# Historical Volatility
|
| 422 |
+
data['Log_Return'] = np.log(data['Close'] / data['Close'].shift(1))
|
| 423 |
+
data['Historical_Volatility'] = data['Log_Return'].rolling(window=252).std() * np.sqrt(252)
|
| 424 |
+
fig15 = px.line(data, x='Date', y='Historical_Volatility', template='seaborn')
|
| 425 |
+
fig15.update_layout(title_text="Historical Volatility (252-day)", title_x=0, margin=dict(l=0, r=10, b=10, t=30), yaxis_title=None, xaxis_title=None)
|
| 426 |
+
g15.plotly_chart(fig15, use_container_width=True)
|
| 427 |
+
|
| 428 |
+
### ............................................... ##
|
| 429 |
+
|
| 430 |
+
# Visualizing the data and want to get the data when hovering over the graph
|
| 431 |
+
st.subheader('Closing Price vs Time Chart')
|
| 432 |
+
fig1 = go.Figure()
|
| 433 |
+
fig1.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Close'))
|
| 434 |
+
fig1.layout.update(hovermode='x')
|
| 435 |
+
# Display the figure in Streamlit
|
| 436 |
+
st.plotly_chart(fig1,use_container_width=True)
|
| 437 |
+
|
| 438 |
+
st.subheader('Closing Price vs Time Chart with 100MA')
|
| 439 |
+
ma100 = data['Close'].rolling(100).mean()
|
| 440 |
+
fig2 = go.Figure()
|
| 441 |
+
# Add traces for 100MA and Closing Price
|
| 442 |
+
fig2.add_trace(go.Scatter(x=data.index, y=ma100, mode='lines', name='100MA'))
|
| 443 |
+
fig2.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Closing Price'))
|
| 444 |
+
fig2.layout.update(hovermode='x')
|
| 445 |
+
# Display the figure in Streamlit
|
| 446 |
+
st.plotly_chart(fig2,use_container_width=True)
|
| 447 |
+
|
| 448 |
+
st.subheader('Closing Price vs Time Chart with 100MA and 200MA')
|
| 449 |
+
ma100 = data['Close'].rolling(100).mean()
|
| 450 |
+
ma200 = data['Close'].rolling(200).mean()
|
| 451 |
+
fig3 = go.Figure()
|
| 452 |
+
# Add traces for 100MA and Closing Price
|
| 453 |
+
fig3.add_trace(go.Scatter(x=data.index, y=ma100, mode='lines', name='100MA'))
|
| 454 |
+
fig3.add_trace(go.Scatter(x=data.index, y=ma200, mode='lines', name='200MA'))
|
| 455 |
+
fig3.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Closing Price'))
|
| 456 |
+
fig3.layout.update(hovermode='x')
|
| 457 |
+
|
| 458 |
+
# Display the figure in Streamlit
|
| 459 |
+
st.plotly_chart(fig3,use_container_width=True)
|
| 460 |
+
|
| 461 |
+
## ............................................... ##
|
| 462 |
+
# Enhanced title with larger font size and a different color
|
| 463 |
+
title = f"<h1 style='color: red; font-size: 25px; text-align: center; '>{stock_name}'s Stock Prediction</h1>"
|
| 464 |
+
st.markdown(title, unsafe_allow_html=True)
|
| 465 |
+
|
| 466 |
+
with st.expander("See Details"):
|
| 467 |
+
# Define the minimum number of days required for predictions
|
| 468 |
+
minimum_days_for_predictions = 100
|
| 469 |
+
|
| 470 |
+
# Check if the available data is less than the minimum required days
|
| 471 |
+
if len(data) < minimum_days_for_predictions:
|
| 472 |
+
st.warning(f"The available data for {stock_name} is less than {minimum_days_for_predictions} days, which is insufficient for predictions.")
|
| 473 |
+
else:
|
| 474 |
+
# Splitting the data into training and testing data
|
| 475 |
+
data_training = pd.DataFrame(data['Close'][0:int(len(data)*0.70)])
|
| 476 |
+
data_testing = pd.DataFrame(data['Close'][int(len(data)*0.70): int(len(data))])
|
| 477 |
+
|
| 478 |
+
# Scaling the data
|
| 479 |
+
scaler = MinMaxScaler(feature_range=(0,1))
|
| 480 |
+
data_training_array = scaler.fit_transform(data_training)
|
| 481 |
+
|
| 482 |
+
# load the model
|
| 483 |
+
model = load_model('best_model_MAPI.h5')
|
| 484 |
+
|
| 485 |
+
# Testing the model
|
| 486 |
+
past_100_days = data_training.tail(100)
|
| 487 |
+
final_df = pd.concat([past_100_days,data_testing], ignore_index=True)
|
| 488 |
+
input_data = scaler.fit_transform(final_df)
|
| 489 |
+
|
| 490 |
+
x_test = []
|
| 491 |
+
y_test = []
|
| 492 |
+
for i in range(100, input_data.shape[0]):
|
| 493 |
+
x_test.append(input_data[i-100:i])
|
| 494 |
+
y_test.append(input_data[i,0])
|
| 495 |
+
|
| 496 |
+
x_test, y_test = np.array(x_test), np.array(y_test)
|
| 497 |
+
|
| 498 |
+
y_predicted = model.predict(x_test)
|
| 499 |
+
|
| 500 |
+
scaler = scaler.scale_
|
| 501 |
+
scale_factor = 1/scaler[0]
|
| 502 |
+
y_predicted = y_predicted * scale_factor
|
| 503 |
+
y_test = y_test * scale_factor
|
| 504 |
+
|
| 505 |
+
# Visualizing the results
|
| 506 |
+
st.subheader('Predictions vs Actual')
|
| 507 |
+
fig4 = go.Figure()
|
| 508 |
+
# Add traces for Actual and Predicted Price
|
| 509 |
+
fig4.add_trace(go.Scatter(x=data.index[-len(y_test):], y=y_test, mode='lines', name='Actual Price'))
|
| 510 |
+
fig4.add_trace(go.Scatter(x=data.index[-len(y_predicted):], y=y_predicted[:,0], mode='lines', name='Predicted Price'))
|
| 511 |
+
fig4.layout.update(hovermode='x')
|
| 512 |
+
# Display the figure in Streamlit
|
| 513 |
+
st.plotly_chart(fig4,use_container_width=True)
|
| 514 |
+
|
| 515 |
+
except Exception as e:
|
| 516 |
+
st.error(f"An error fetching stock information: {str(e)}")
|
pages/π_Stock_Comparison.py
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import pandas as pd
|
| 2 |
+
import numpy as np
|
| 3 |
+
import matplotlib.pyplot as plt
|
| 4 |
+
import pandas_datareader.data as web
|
| 5 |
+
import datetime as dt
|
| 6 |
+
import yfinance as yf
|
| 7 |
+
from sklearn.preprocessing import MinMaxScaler
|
| 8 |
+
from keras.models import load_model
|
| 9 |
+
import streamlit as st
|
| 10 |
+
import plotly.graph_objects as go
|
| 11 |
+
import base64
|
| 12 |
+
import plotly.express as px
|
| 13 |
+
from datetime import datetime
|
| 14 |
+
|
| 15 |
+
st.set_page_config(page_title='Stock Comparison', layout='wide', page_icon='π')
|
| 16 |
+
|
| 17 |
+
stock_tickers = {
|
| 18 |
+
"MAPI":"MAPI.JK","MAP Aktif": "MAPA.JK","MAP Boga": "MAPB.JK",
|
| 19 |
+
"Tesla": "TSLA", "Apple": "AAPL", "Microsoft": "MSFT", "Google": "GOOGL",
|
| 20 |
+
"Facebook": "FB", "Amazon": "AMZN", "Netflix": "NFLX", "Alphabet": "GOOG",
|
| 21 |
+
"Nvidia": "NVDA", "Paypal": "PYPL", "Adobe": "ADBE", "Intel": "INTC",
|
| 22 |
+
"Cisco": "CSCO", "Comcast": "CMCSA", "Pepsi": "PEP", "Costco": "COST",
|
| 23 |
+
"Starbucks": "SBUX", "Walmart": "WMT", "Disney": "DIS", "Visa": "V",
|
| 24 |
+
"Mastercard": "MA", "Boeing": "BA", "IBM": "IBM", "McDonalds": "MCD",
|
| 25 |
+
"Nike": "NKE", "Exxon": "XOM", "Chevron": "CVX", "Verizon": "VZ",
|
| 26 |
+
"AT&T": "T", "Home Depot": "HD", "Salesforce": "CRM", "Oracle": "ORCL",
|
| 27 |
+
"Qualcomm": "QCOM", "AMD": "AMD"
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
st.title("Stock Comparison and Analysis")
|
| 31 |
+
|
| 32 |
+
# Sidebar for stock selection and date range specification
|
| 33 |
+
st.sidebar.header("Select Stocks and Date Ranges")
|
| 34 |
+
|
| 35 |
+
#stock1 = st.sidebar.selectbox("Select Stock 1", list(stock_tickers.keys()), key="stock1_selectbox")
|
| 36 |
+
#stock2 = st.sidebar.selectbox("Select Stock 2", list(stock_tickers.keys()), key="stock2_selectbox")
|
| 37 |
+
|
| 38 |
+
stock1 = st.sidebar.text_input("Select a Stock", "MAPI.JK")
|
| 39 |
+
stock2 = st.sidebar.text_input("Select a Stock", "MAPA.JK")
|
| 40 |
+
|
| 41 |
+
start_date_stock1 = st.sidebar.date_input(f"Start date for {stock1}", datetime(2018, 1, 1), key=f"start_date_{stock1}")
|
| 42 |
+
end_date_stock1 = st.sidebar.date_input(f"End date for {stock1}", datetime(2023, 12, 1), key=f"end_date_{stock1}")
|
| 43 |
+
start_date_stock2 = st.sidebar.date_input(f"Start date for {stock2}", datetime(2018, 1, 1), key=f"start_date_{stock2}")
|
| 44 |
+
end_date_stock2 = st.sidebar.date_input(f"End date for {stock2}", datetime(2023, 12, 1), key=f"end_date_{stock2}")
|
| 45 |
+
|
| 46 |
+
# Button to trigger the comparison
|
| 47 |
+
if st.sidebar.button("Compare"):
|
| 48 |
+
# Load data for both stocks
|
| 49 |
+
data_stock1 = yf.download(stock1, start=start_date_stock1, end=end_date_stock1)
|
| 50 |
+
data_stock2 = yf.download(stock2, start=start_date_stock2, end=end_date_stock2)
|
| 51 |
+
|
| 52 |
+
# Plotting the data
|
| 53 |
+
fig = go.Figure()
|
| 54 |
+
|
| 55 |
+
fig.add_trace(go.Scatter(x=data_stock1.index, y=data_stock1['Close'], mode='lines', name=f'{stock1}'))
|
| 56 |
+
fig.add_trace(go.Scatter(x=data_stock2.index, y=data_stock2['Close'], mode='lines', name=f'{stock2}'))
|
| 57 |
+
|
| 58 |
+
fig.update_layout(title=f"Comparison of {stock1} and {stock2}", xaxis_title="Date", yaxis_title="Closing Price")
|
| 59 |
+
|
| 60 |
+
st.plotly_chart(fig)
|
| 61 |
+
|
| 62 |
+
st.sidebar.markdown("----")
|
| 63 |
+
st.sidebar.markdown("Β© 2023 Stock Comparison and Analysis")
|