|
import streamlit as st |
|
import yfinance as yf |
|
import pandas as pd |
|
import matplotlib.pyplot as plt |
|
from statsmodels.tsa.arima.model import ARIMA |
|
from sklearn.preprocessing import MinMaxScaler |
|
from tensorflow.keras.models import Sequential |
|
from tensorflow.keras.layers import Dense, LSTM, GRU |
|
import numpy as np |
|
|
|
|
|
def get_stock_data(symbol, start_date, end_date): |
|
stock_data = yf.download(symbol, start=start_date, end=end_date) |
|
return stock_data['Close'] |
|
|
|
|
|
def prepare_data(data): |
|
scaler = MinMaxScaler(feature_range=(0, 1)) |
|
scaled_data = scaler.fit_transform(data.values.reshape(-1, 1)) |
|
return scaled_data, scaler |
|
|
|
|
|
def create_lstm_model(input_shape): |
|
model = Sequential() |
|
model.add(LSTM(units=50, return_sequences=True, input_shape=input_shape)) |
|
model.add(LSTM(units=50, return_sequences=True)) |
|
model.add(LSTM(units=50)) |
|
model.add(Dense(units=1)) |
|
model.compile(optimizer='adam', loss='mean_squared_error') |
|
return model |
|
|
|
|
|
def create_gru_model(input_shape): |
|
model = Sequential() |
|
model.add(GRU(units=50, return_sequences=True, input_shape=input_shape)) |
|
model.add(GRU(units=50, return_sequences=True)) |
|
model.add(GRU(units=50)) |
|
model.add(Dense(units=1)) |
|
model.compile(optimizer='adam', loss='mean_squared_error') |
|
return model |
|
|
|
|
|
def lstm_gru_forecast(data, model_type, steps): |
|
scaled_data, scaler = prepare_data(data) |
|
input_data = scaled_data.reshape(-1, 1) |
|
|
|
|
|
train_size = int(len(input_data) * 0.80) |
|
train_data, test_data = input_data[0:train_size, :], input_data[train_size:len(input_data), :] |
|
|
|
x_train, y_train = [], [] |
|
for i in range(60, len(train_data)): |
|
x_train.append(train_data[i - 60:i, 0]) |
|
y_train.append(train_data[i, 0]) |
|
|
|
x_train, y_train = np.array(x_train), np.array(y_train) |
|
x_train = np.reshape(x_train, (x_train.shape[0], x_train.shape[1], 1)) |
|
|
|
|
|
input_shape = (x_train.shape[1], 1) |
|
if model_type == 'lstm': |
|
model = create_lstm_model(input_shape) |
|
elif model_type == 'gru': |
|
model = create_gru_model(input_shape) |
|
|
|
model.fit(x_train, y_train, epochs=25, batch_size=32) |
|
|
|
|
|
inputs = input_data[len(input_data) - len(test_data) - 60:] |
|
inputs = inputs.reshape(-1, 1) |
|
x_test = [] |
|
for i in range(60, len(inputs)): |
|
x_test.append(inputs[i - 60:i, 0]) |
|
x_test = np.array(x_test) |
|
|
|
x_test = np.reshape(x_test, (x_test.shape[0], x_test.shape[1], 1)) |
|
predicted_prices = model.predict(x_test) |
|
predicted_prices = scaler.inverse_transform(predicted_prices) |
|
|
|
|
|
forecast_index = pd.date_range(start=data.index[-1], periods=steps + 1, freq=data.index.freq) |
|
|
|
return pd.Series(predicted_prices.flatten(), index=forecast_index[1:]) |
|
|
|
|
|
def ensemble_forecast(predictions_list): |
|
return pd.DataFrame(predictions_list).mean(axis=0) |
|
|
|
|
|
def arima_forecast(data, p, d, q, steps): |
|
|
|
for i in range(d): |
|
data_diff = np.diff(data) |
|
data = data_diff |
|
|
|
|
|
ar_coef = np.zeros(p) if p > 0 else [] |
|
ma_coef = np.zeros(q) if q > 0 else [] |
|
|
|
|
|
predictions = list(data[:p]) |
|
|
|
|
|
for i in range(len(data) - p): |
|
ar_term = sum(ar_coef[j] * data[i + p - j - 1] for j in range(p)) |
|
ma_term = sum(ma_coef[j] * (data[i + p - j - 1] - predictions[-1]) for j in range(q)) |
|
next_prediction = data[i + p] + ar_term + ma_term |
|
predictions.append(next_prediction) |
|
|
|
|
|
if i + p + 1 < len(data): |
|
ar_coef = ar_coef + (2.0 / (i + p + 2)) * (data[i + p + 1] - next_prediction) * np.flip(data[i:i + p]) |
|
ma_coef = ma_coef + (2.0 / (i + p + 2)) * (data[i + p + 1] - next_prediction) * np.flip(predictions[i - q + 1:i + 1]) |
|
|
|
|
|
for i in range(d): |
|
predictions = np.cumsum([data[p - 1]] + predictions) |
|
|
|
return predictions[-steps:] |
|
|
|
|
|
|
|
def main(): |
|
st.title("Stock Price Forecasting App") |
|
|
|
|
|
symbol = st.sidebar.text_input("Enter Stock Symbol", value='AAPL') |
|
start_date = st.sidebar.date_input("Select Start Date", pd.to_datetime('2021-01-01')) |
|
end_date = st.sidebar.date_input("Select End Date", pd.to_datetime('2022-01-01')) |
|
stock_prices = get_stock_data(symbol, start_date, end_date) |
|
|
|
|
|
p = st.sidebar.slider("AR Component (p)", min_value=0, max_value=10, value=3) |
|
d = st.sidebar.slider("Differencing (d)", min_value=0, max_value=5, value=0) |
|
q = st.sidebar.slider("MA Component (q)", min_value=0, max_value=10, value=0) |
|
arima_forecast_steps = st.sidebar.slider("ARIMA Forecast Steps", min_value=1, max_value=100, value=30) |
|
|
|
|
|
lstm_gru_forecast_steps = st.sidebar.slider("LSTM/GRU Forecast Steps", min_value=1, max_value=100, value=30) |
|
|
|
|
|
if st.sidebar.button("Run Custom ARIMA Forecast"): |
|
arima_predictions_custom = arima_forecast(stock_prices.values, p, d, q, arima_forecast_steps) |
|
arima_predictions_custom = pd.Series(arima_predictions_custom, index=pd.date_range(start=stock_prices.index[-1], periods=arima_forecast_steps + 1, freq=stock_prices.index.freq)) |
|
|
|
|
|
st.subheader("Custom ARIMA Forecast") |
|
st.line_chart(pd.concat([stock_prices, arima_predictions_custom], axis=1).rename(columns={0: "ARIMA Forecast"})) |
|
|
|
|
|
if st.sidebar.button("Run LSTM Forecast"): |
|
lstm_predictions = lstm_gru_forecast(stock_prices, 'lstm', lstm_gru_forecast_steps) |
|
|
|
|
|
st.subheader("LSTM Forecast") |
|
st.line_chart(pd.concat([stock_prices, pd.Series(lstm_predictions, index=pd.date_range(start=stock_prices.index[-1], periods=lstm_gru_forecast_steps + 1, freq=stock_prices.index.freq))], axis=1).rename(columns={0: "LSTM Forecast"})) |
|
|
|
|
|
if st.sidebar.button("Run GRU Forecast"): |
|
gru_predictions = lstm_gru_forecast(stock_prices, 'gru', lstm_gru_forecast_steps) |
|
|
|
|
|
st.subheader("GRU Forecast") |
|
st.line_chart(pd.concat([stock_prices, pd.Series(gru_predictions, index=pd.date_range(start=stock_prices.index[-1], periods=lstm_gru_forecast_steps + 1, freq=stock_prices.index.freq))], axis=1).rename(columns={0: "GRU Forecast"})) |
|
|
|
|
|
if st.sidebar.button("Run Ensemble Forecast"): |
|
ensemble_predictions = ensemble_forecast([arima_predictions_custom, lstm_predictions, gru_predictions]) |
|
|
|
|
|
st.subheader("Ensemble Forecast") |
|
st.line_chart(pd.concat([stock_prices, ensemble_predictions], axis=1).rename(columns={0: "Ensemble Forecast"})) |
|
|
|
|
|
st.subheader("Historical Stock Prices") |
|
st.line_chart(stock_prices) |
|
|
|
if __name__ == "__main__": |
|
main() |