File size: 7,643 Bytes
c28f349
ebf57c0
4eaa6d3
c28f349
 
4eaa6d3
 
 
c28f349
ebf57c0
 
 
 
 
 
4eaa6d3
 
 
 
 
 
 
c28f349
4eaa6d3
c28f349
 
 
4eaa6d3
 
 
 
 
c28f349
4eaa6d3
c28f349
 
 
4eaa6d3
 
 
 
c28f349
 
 
 
4eaa6d3
c28f349
 
 
4eaa6d3
c28f349
 
 
 
 
 
 
 
 
 
 
 
 
 
4eaa6d3
c28f349
4eaa6d3
c28f349
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4eaa6d3
 
 
3bb41b1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ebf57c0
80071c9
3bb41b1
 
 
 
 
 
80071c9
 
3bb41b1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
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

# Function to load stock data using yfinance
def get_stock_data(symbol, start_date, end_date):
    stock_data = yf.download(symbol, start=start_date, end=end_date)
    return stock_data['Close']

# Function to normalize data and prepare it for LSTM/GRU
def prepare_data(data):
    scaler = MinMaxScaler(feature_range=(0, 1))
    scaled_data = scaler.fit_transform(data.values.reshape(-1, 1))
    return scaled_data, scaler

# Function to create LSTM model
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

# Function to create GRU 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

# Function to fit LSTM/GRU model and make predictions
def lstm_gru_forecast(data, model_type, steps):
    scaled_data, scaler = prepare_data(data)
    input_data = scaled_data.reshape(-1, 1)

    # Split data into training and testing sets
    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))

    # Create and fit the model
    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)

    # Make predictions
    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)

    # Create an index for the forecasted values
    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:])

# Function to create an ensemble forecast by averaging predictions
def ensemble_forecast(predictions_list):
    return pd.DataFrame(predictions_list).mean(axis=0)

# Function to fit ARIMA model and make predictions
def arima_forecast(data, p, d, q, steps):
    # Differencing
    for i in range(d):
        data_diff = np.diff(data)
        data = data_diff

    # Autoregressive (AR) and Moving Average (MA) components
    ar_coef = np.zeros(p) if p > 0 else []
    ma_coef = np.zeros(q) if q > 0 else []

    # Initial prediction
    predictions = list(data[:p])

    # ARIMA forecasting
    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)

        # Update coefficients using online learning (optional)
        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])

    # Inverse differencing
    for i in range(d):
        predictions = np.cumsum([data[p - 1]] + predictions)

    return predictions[-steps:]

# Streamlit App
# Streamlit App
def main():
    st.title("Stock Price Forecasting App")

    # Load stock data using Streamlit sidebar
    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)

    # ARIMA parameters using Streamlit sliders
    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 and GRU parameters using Streamlit sliders
    lstm_gru_forecast_steps = st.sidebar.slider("LSTM/GRU Forecast Steps", min_value=1, max_value=100, value=30)

    # Custom ARIMA Forecast using Streamlit button
    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))

        # Display ARIMA Forecast Plot
        st.subheader("Custom ARIMA Forecast")
        st.line_chart(pd.concat([stock_prices, arima_predictions_custom], axis=1).rename(columns={0: "ARIMA Forecast"}))

    # LSTM Forecast using Streamlit button
    if st.sidebar.button("Run LSTM Forecast"):
        lstm_predictions = lstm_gru_forecast(stock_prices, 'lstm', lstm_gru_forecast_steps)

        # Display LSTM Forecast Plot
        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"}))

    # GRU Forecast using Streamlit button
    if st.sidebar.button("Run GRU Forecast"):
        gru_predictions = lstm_gru_forecast(stock_prices, 'gru', lstm_gru_forecast_steps)

        # Display GRU Forecast Plot
        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"}))

    # Ensemble Forecast using Streamlit button
    if st.sidebar.button("Run Ensemble Forecast"):
        ensemble_predictions = ensemble_forecast([arima_predictions_custom, lstm_predictions, gru_predictions])

        # Display Ensemble Forecast Plot
        st.subheader("Ensemble Forecast")
        st.line_chart(pd.concat([stock_prices, ensemble_predictions], axis=1).rename(columns={0: "Ensemble Forecast"}))

    # Plotting Historical Stock Prices
    st.subheader("Historical Stock Prices")
    st.line_chart(stock_prices)

if __name__ == "__main__":
    main()