Update app.py
Browse files
app.py
CHANGED
@@ -41,25 +41,28 @@ class StockPredictor:
|
|
41 |
self.model = None
|
42 |
|
43 |
def preprocess_data(self):
|
44 |
-
# Prophet requires columns named 'ds' and 'y'
|
45 |
self.data = self.data.reset_index()
|
46 |
self.data = self.data.rename(columns={'Date': 'ds', 'Close': 'y'})
|
47 |
|
48 |
-
# Add
|
49 |
-
self.data['SMA_20'] = self.data['y']
|
50 |
-
self.data['EMA_20'] = self.data['y']
|
51 |
-
self.data['RSI'] =
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
|
53 |
# Handle NaN values
|
54 |
self.data = self.data.dropna()
|
55 |
|
56 |
-
def calculate_rsi(self, prices, periods=14):
|
57 |
-
delta = prices.diff()
|
58 |
-
gain = (delta.where(delta > 0, 0)).rolling(window=periods).mean()
|
59 |
-
loss = (-delta.where(delta < 0, 0)).rolling(window=periods).mean()
|
60 |
-
rs = gain / loss
|
61 |
-
return 100 - (100 / (1 + rs))
|
62 |
-
|
63 |
def train_model(self):
|
64 |
try:
|
65 |
self.model = Prophet(
|
@@ -72,9 +75,8 @@ class StockPredictor:
|
|
72 |
)
|
73 |
|
74 |
# Add additional regressors
|
75 |
-
|
76 |
-
|
77 |
-
self.model.add_regressor('RSI')
|
78 |
|
79 |
self.model.fit(self.data)
|
80 |
return True
|
@@ -87,8 +89,8 @@ class StockPredictor:
|
|
87 |
future = self.model.make_future_dataframe(periods=days)
|
88 |
|
89 |
# Add regressor values for future dates
|
90 |
-
for
|
91 |
-
future[
|
92 |
|
93 |
forecast = self.model.predict(future)
|
94 |
return forecast
|
@@ -111,6 +113,11 @@ class StockPredictor:
|
|
111 |
|
112 |
return mse, mape, rmse
|
113 |
|
|
|
|
|
|
|
|
|
|
|
114 |
def fetch_stock_data(ticker):
|
115 |
try:
|
116 |
end_date = datetime.now()
|
@@ -180,6 +187,24 @@ def create_prediction_plot(data, predicted_data, company_name):
|
|
180 |
name='Predicted Data',
|
181 |
line=dict(color='yellow')
|
182 |
))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
183 |
|
184 |
fig.update_layout(
|
185 |
title=f'{company_name} Stock Price Prediction',
|
@@ -246,7 +271,7 @@ def main():
|
|
246 |
predict_stock_prices()
|
247 |
|
248 |
def test_model():
|
249 |
-
st.header("Test Prophet Model")
|
250 |
|
251 |
col1, col2 = st.columns(2)
|
252 |
|
@@ -266,13 +291,11 @@ def test_model():
|
|
266 |
st.write(data.describe())
|
267 |
st.dataframe(data.head())
|
268 |
|
269 |
-
st.markdown(get_table_download_link(data), unsafe_allow_html=True)
|
270 |
-
|
271 |
split_index = int(len(data) * (1 - test_split))
|
272 |
train_data = data.iloc[:split_index]
|
273 |
test_data = data.iloc[split_index:]
|
274 |
|
275 |
-
predictor =
|
276 |
predictor.preprocess_data()
|
277 |
if predictor.train_model():
|
278 |
test_pred = predictor.predict(days=len(test_data))
|
@@ -290,6 +313,18 @@ def test_model():
|
|
290 |
|
291 |
plot = create_test_plot(predictor.data, test_data.reset_index().rename(columns={'Date': 'ds', 'Close': 'y'}), test_pred, company_name)
|
292 |
st.plotly_chart(plot, use_container_width=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
293 |
else:
|
294 |
st.error("Failed to evaluate the model. The evaluation metrics are None.")
|
295 |
else:
|
@@ -298,7 +333,7 @@ def test_model():
|
|
298 |
st.error("Failed to train the Prophet model. Please try a different dataset.")
|
299 |
|
300 |
def predict_stock_prices():
|
301 |
-
st.header("Predict Stock Prices")
|
302 |
|
303 |
col1, col2 = st.columns(2)
|
304 |
|
@@ -318,9 +353,7 @@ def predict_stock_prices():
|
|
318 |
st.write(data.describe())
|
319 |
st.dataframe(data.head())
|
320 |
|
321 |
-
|
322 |
-
|
323 |
-
predictor = StockPredictor(data)
|
324 |
predictor.preprocess_data()
|
325 |
if predictor.train_model():
|
326 |
predictions = predictor.predict(days=days_to_predict)
|
@@ -337,6 +370,17 @@ def predict_stock_prices():
|
|
337 |
pred_df.columns = ['Date', 'Predicted Price', 'Lower Bound', 'Upper Bound']
|
338 |
st.dataframe(pred_df)
|
339 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
340 |
news = fetch_news(company_name)
|
341 |
st.subheader("Latest News")
|
342 |
for item in news:
|
|
|
41 |
self.model = None
|
42 |
|
43 |
def preprocess_data(self):
|
|
|
44 |
self.data = self.data.reset_index()
|
45 |
self.data = self.data.rename(columns={'Date': 'ds', 'Close': 'y'})
|
46 |
|
47 |
+
# Add technical indicators
|
48 |
+
self.data['SMA_20'] = SMAIndicator(close=self.data['y'], window=20).sma_indicator()
|
49 |
+
self.data['EMA_20'] = EMAIndicator(close=self.data['y'], window=20).ema_indicator()
|
50 |
+
self.data['RSI'] = RSIIndicator(close=self.data['y'], window=14).rsi()
|
51 |
+
bb = BollingerBands(close=self.data['y'], window=20, window_dev=2)
|
52 |
+
self.data['BB_high'] = bb.bollinger_hband()
|
53 |
+
self.data['BB_low'] = bb.bollinger_lband()
|
54 |
+
|
55 |
+
# Add lagged features
|
56 |
+
self.data['lag_1'] = self.data['y'].shift(1)
|
57 |
+
self.data['lag_7'] = self.data['y'].shift(7)
|
58 |
+
|
59 |
+
# Add rolling statistics
|
60 |
+
self.data['rolling_mean_7'] = self.data['y'].rolling(window=7).mean()
|
61 |
+
self.data['rolling_std_7'] = self.data['y'].rolling(window=7).std()
|
62 |
|
63 |
# Handle NaN values
|
64 |
self.data = self.data.dropna()
|
65 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
66 |
def train_model(self):
|
67 |
try:
|
68 |
self.model = Prophet(
|
|
|
75 |
)
|
76 |
|
77 |
# Add additional regressors
|
78 |
+
for column in ['SMA_20', 'EMA_20', 'RSI', 'BB_high', 'BB_low', 'lag_1', 'lag_7', 'rolling_mean_7', 'rolling_std_7']:
|
79 |
+
self.model.add_regressor(column)
|
|
|
80 |
|
81 |
self.model.fit(self.data)
|
82 |
return True
|
|
|
89 |
future = self.model.make_future_dataframe(periods=days)
|
90 |
|
91 |
# Add regressor values for future dates
|
92 |
+
for column in ['SMA_20', 'EMA_20', 'RSI', 'BB_high', 'BB_low', 'lag_1', 'lag_7', 'rolling_mean_7', 'rolling_std_7']:
|
93 |
+
future[column] = self.data[column].iloc[-1] # Use last known value
|
94 |
|
95 |
forecast = self.model.predict(future)
|
96 |
return forecast
|
|
|
113 |
|
114 |
return mse, mape, rmse
|
115 |
|
116 |
+
def cross_validate_model(self):
|
117 |
+
df_cv = cross_validation(self.model, initial='730 days', period='180 days', horizon='90 days')
|
118 |
+
df_p = performance_metrics(df_cv)
|
119 |
+
return df_p
|
120 |
+
|
121 |
def fetch_stock_data(ticker):
|
122 |
try:
|
123 |
end_date = datetime.now()
|
|
|
187 |
name='Predicted Data',
|
188 |
line=dict(color='yellow')
|
189 |
))
|
190 |
+
|
191 |
+
# Add prediction intervals
|
192 |
+
fig.add_trace(go.Scatter(
|
193 |
+
x=future_dates,
|
194 |
+
y=predicted_data['yhat_upper'],
|
195 |
+
mode='lines',
|
196 |
+
line=dict(width=0),
|
197 |
+
showlegend=False
|
198 |
+
))
|
199 |
+
fig.add_trace(go.Scatter(
|
200 |
+
x=future_dates,
|
201 |
+
y=predicted_data['yhat_lower'],
|
202 |
+
mode='lines',
|
203 |
+
line=dict(width=0),
|
204 |
+
fillcolor='rgba(255, 255, 0, 0.3)',
|
205 |
+
fill='tonexty',
|
206 |
+
name='Prediction Interval'
|
207 |
+
))
|
208 |
|
209 |
fig.update_layout(
|
210 |
title=f'{company_name} Stock Price Prediction',
|
|
|
271 |
predict_stock_prices()
|
272 |
|
273 |
def test_model():
|
274 |
+
st.header("Test Enhanced Prophet Model")
|
275 |
|
276 |
col1, col2 = st.columns(2)
|
277 |
|
|
|
291 |
st.write(data.describe())
|
292 |
st.dataframe(data.head())
|
293 |
|
|
|
|
|
294 |
split_index = int(len(data) * (1 - test_split))
|
295 |
train_data = data.iloc[:split_index]
|
296 |
test_data = data.iloc[split_index:]
|
297 |
|
298 |
+
predictor = EnhancedStockPredictor(train_data)
|
299 |
predictor.preprocess_data()
|
300 |
if predictor.train_model():
|
301 |
test_pred = predictor.predict(days=len(test_data))
|
|
|
313 |
|
314 |
plot = create_test_plot(predictor.data, test_data.reset_index().rename(columns={'Date': 'ds', 'Close': 'y'}), test_pred, company_name)
|
315 |
st.plotly_chart(plot, use_container_width=True)
|
316 |
+
|
317 |
+
# Cross-validation results
|
318 |
+
st.subheader("Cross-Validation Results")
|
319 |
+
cv_results = predictor.cross_validate_model()
|
320 |
+
st.dataframe(cv_results)
|
321 |
+
|
322 |
+
# Feature importance
|
323 |
+
st.subheader("Feature Importance")
|
324 |
+
feature_importance = pd.DataFrame(predictor.model.params['regressor_coefficients'].items(), columns=['Feature', 'Importance'])
|
325 |
+
feature_importance = feature_importance.sort_values('Importance', ascending=False)
|
326 |
+
fig = px.bar(feature_importance, x='Feature', y='Importance', title='Feature Importance')
|
327 |
+
st.plotly_chart(fig, use_container_width=True)
|
328 |
else:
|
329 |
st.error("Failed to evaluate the model. The evaluation metrics are None.")
|
330 |
else:
|
|
|
333 |
st.error("Failed to train the Prophet model. Please try a different dataset.")
|
334 |
|
335 |
def predict_stock_prices():
|
336 |
+
st.header("Predict Stock Prices with Enhanced Model")
|
337 |
|
338 |
col1, col2 = st.columns(2)
|
339 |
|
|
|
353 |
st.write(data.describe())
|
354 |
st.dataframe(data.head())
|
355 |
|
356 |
+
predictor = EnhancedStockPredictor(data)
|
|
|
|
|
357 |
predictor.preprocess_data()
|
358 |
if predictor.train_model():
|
359 |
predictions = predictor.predict(days=days_to_predict)
|
|
|
370 |
pred_df.columns = ['Date', 'Predicted Price', 'Lower Bound', 'Upper Bound']
|
371 |
st.dataframe(pred_df)
|
372 |
|
373 |
+
# Component-wise forecast
|
374 |
+
st.subheader("Forecast Components")
|
375 |
+
fig = predictor.model.plot_components(predictions)
|
376 |
+
st.pyplot(fig)
|
377 |
+
|
378 |
+
# Changepoints
|
379 |
+
st.subheader("Detected Changepoints")
|
380 |
+
fig = predictor.model.plot(predictions)
|
381 |
+
a = add_changepoints_to_plot(fig.gca(), predictor.model, predictions)
|
382 |
+
st.pyplot(fig)
|
383 |
+
|
384 |
news = fetch_news(company_name)
|
385 |
st.subheader("Latest News")
|
386 |
for item in news:
|