Spaces:
Sleeping
Sleeping
Coder commited on
Commit ·
b4eb7a7
1
Parent(s): 98ef6ad
initial commit
Browse files- README.md +18 -1
- app.py +176 -0
- requirements.txt +9 -0
README.md
CHANGED
|
@@ -10,4 +10,21 @@ pinned: false
|
|
| 10 |
license: apache-2.0
|
| 11 |
---
|
| 12 |
|
| 13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
license: apache-2.0
|
| 11 |
---
|
| 12 |
|
| 13 |
+
# 📈 Stock Prediction on NSE Stocks
|
| 14 |
+
|
| 15 |
+
Welcome to the Stock Prediction app! This application uses the Prophet forecasting model to predict future stock prices for companies listed on the NSE (National Stock Exchange of India).
|
| 16 |
+
|
| 17 |
+
## 🚀 Features
|
| 18 |
+
|
| 19 |
+
- **Sentiment Analysis:** Get sentiment analysis (Positive, Negative, Neutral) based on the last available stock price and predicted price.
|
| 20 |
+
- **Flexible Training Period:** Choose from different training periods (1 week, 1 month, 1 year, 10 years).
|
| 21 |
+
- **Custom Forecast Horizon:** Predict stock prices for the next day, week, or month.
|
| 22 |
+
- **Performance Metrics:** Evaluate the accuracy of predictions with Mean Absolute Error (MAE), Mean Squared Error (MSE), and Root Mean Squared Error (RMSE).
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
## 📋 Usage
|
| 26 |
+
|
| 27 |
+
1. **Select Ticker Symbol:** Choose a ticker symbol from the sidebar.
|
| 28 |
+
2. **Select Training Period:** Choose the period over which the model should be trained.
|
| 29 |
+
3. **Select Forecast Horizon:** Choose the period for which you want to predict stock prices.
|
| 30 |
+
4. **Forecast Stock Prices:** Click the "Forecast Stock Prices" button to generate predictions.
|
app.py
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import pandas as pd
|
| 3 |
+
import numpy as np
|
| 4 |
+
from prophet import Prophet
|
| 5 |
+
import yfinance as yf
|
| 6 |
+
from sklearn.metrics import mean_absolute_error, mean_squared_error
|
| 7 |
+
from prophet.plot import plot_plotly, plot_components_plotly
|
| 8 |
+
|
| 9 |
+
# List of ticker symbols
|
| 10 |
+
ticker_symbols = ['RELIANCE', 'TCS', 'HDFCBANK', 'ICICIBANK', 'BHARTIARTL', 'SBIN', 'INFY', 'LICI', 'ITC', 'HINDUNILVR', 'LT', 'BAJFINANCE', 'HCLTECH', 'MARUTI', 'SUNPHARMA', 'ADANIENT', 'KOTAKBANK', 'TITAN', 'ONGC', 'TATAMOTORS', 'NTPC', 'AXISBANK', 'DMART', 'ADANIGREEN', 'ADANIPORTS', 'ULTRACEMCO', 'ASIANPAINT', 'COALINDIA', 'BAJAJFINSV', 'BAJAJ-AUTO', 'POWERGRID', 'NESTLEIND', 'WIPRO', 'M&M', 'IOC', 'JIOFIN', 'HAL', 'DLF', 'ADANIPOWER', 'JSWSTEEL', 'TATASTEEL', 'SIEMENS', 'IRFC', 'VBL', 'ZOMATO', 'PIDILITIND', 'GRASIM', 'SBILIFE', 'BEL', 'LTIM', 'TRENT', 'PNB', 'INDIGO', 'BANKBARODA', 'HDFCLIFE', 'ABB', 'BPCL', 'PFC', 'GODREJCP', 'TATAPOWER', 'HINDALCO', 'HINDZINC', 'TECHM', 'AMBUJACEM', 'INDUSINDBK', 'CIPLA', 'GAIL']
|
| 11 |
+
|
| 12 |
+
# Function to fetch stock data from Yahoo Finance
|
| 13 |
+
def fetch_stock_data(ticker_symbol, start_date, end_date):
|
| 14 |
+
ticker_symbol = ticker_symbol +".NS"
|
| 15 |
+
stock_data = yf.download(ticker_symbol, start=start_date, end=end_date)
|
| 16 |
+
df = stock_data[['Adj Close']].reset_index()
|
| 17 |
+
df = df.rename(columns={'Date': 'ds', 'Adj Close': 'y'})
|
| 18 |
+
# df.to_csv(f"{ticker_symbol}.csv")
|
| 19 |
+
return df
|
| 20 |
+
|
| 21 |
+
# Function to train the Prophet model
|
| 22 |
+
def train_prophet_model(df):
|
| 23 |
+
model = Prophet()
|
| 24 |
+
model.fit(df)
|
| 25 |
+
return model
|
| 26 |
+
|
| 27 |
+
# Function to make the forecast
|
| 28 |
+
def make_forecast(model, periods):
|
| 29 |
+
future = model.make_future_dataframe(periods=periods)
|
| 30 |
+
forecast = model.predict(future)
|
| 31 |
+
return forecast
|
| 32 |
+
|
| 33 |
+
# Function to calculate performance metrics
|
| 34 |
+
def calculate_performance_metrics(actual, predicted):
|
| 35 |
+
mae = mean_absolute_error(actual, predicted)
|
| 36 |
+
mse = mean_squared_error(actual, predicted)
|
| 37 |
+
rmse = np.sqrt(mse)
|
| 38 |
+
return {'MAE': mae, 'MSE': mse, 'RMSE': rmse}
|
| 39 |
+
|
| 40 |
+
# Function to determine sentiment
|
| 41 |
+
def determine_sentiment(actual, predicted):
|
| 42 |
+
if actual > predicted:
|
| 43 |
+
sentiment = 'Negative'
|
| 44 |
+
elif actual < predicted:
|
| 45 |
+
sentiment = 'Positive'
|
| 46 |
+
else:
|
| 47 |
+
sentiment = 'Neutral'
|
| 48 |
+
return sentiment
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
# Streamlit app
|
| 52 |
+
def main():
|
| 53 |
+
st.title('Stock Prediction on NSE Stocks')
|
| 54 |
+
|
| 55 |
+
# Set up the layout
|
| 56 |
+
st.sidebar.header('User Input Parameters')
|
| 57 |
+
ticker_symbol = st.sidebar.selectbox('Enter Ticker Symbol', options=ticker_symbols, index=0)
|
| 58 |
+
|
| 59 |
+
# Dropdown for training period selection
|
| 60 |
+
training_period = st.sidebar.selectbox('Select Training Period',
|
| 61 |
+
options=['1 week', '1 month', '1 year', '10 years'])
|
| 62 |
+
|
| 63 |
+
# Calculate start date and end date based on training period
|
| 64 |
+
if training_period == '1 week':
|
| 65 |
+
start_date = pd.to_datetime('today') - pd.DateOffset(weeks=1)
|
| 66 |
+
elif training_period == '1 month':
|
| 67 |
+
start_date = pd.to_datetime('today') - pd.DateOffset(months=1)
|
| 68 |
+
elif training_period == '1 year':
|
| 69 |
+
start_date = pd.to_datetime('today') - pd.DateOffset(years=1)
|
| 70 |
+
elif training_period == '10 years':
|
| 71 |
+
start_date = pd.to_datetime('today') - pd.DateOffset(years=10)
|
| 72 |
+
|
| 73 |
+
end_date = pd.to_datetime('today')
|
| 74 |
+
|
| 75 |
+
# Fetching the data for the selected training period
|
| 76 |
+
df = fetch_stock_data(ticker_symbol, start_date, end_date)
|
| 77 |
+
|
| 78 |
+
# Dropdown for forecast horizon selection
|
| 79 |
+
forecast_horizon = st.sidebar.selectbox('Forecast Horizon',
|
| 80 |
+
options=['Next day', 'Next week', 'Next month'],
|
| 81 |
+
format_func=lambda x: x.capitalize())
|
| 82 |
+
|
| 83 |
+
# Convert the selected horizon to days
|
| 84 |
+
horizon_mapping = {'Next day': 1, 'Next week': 7, 'Next month': 30}
|
| 85 |
+
forecast_days = horizon_mapping[forecast_horizon]
|
| 86 |
+
|
| 87 |
+
if st.sidebar.button('Forecast Stock Prices'):
|
| 88 |
+
with st.spinner('Training model...'):
|
| 89 |
+
model = train_prophet_model(df)
|
| 90 |
+
forecast = make_forecast(model, forecast_days)
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
forecast_reversed = forecast[['ds', 'yhat', 'yhat_lower', 'yhat_upper']].iloc[-forecast_days:].iloc[::-1]
|
| 94 |
+
|
| 95 |
+
st.markdown("""
|
| 96 |
+
*The prediction was made using the Prophet forecasting model. The model was trained on historical stock data and used to forecast future prices based on the observed trends and patterns.*
|
| 97 |
+
""")
|
| 98 |
+
st.subheader(f'Forecast Summary for {ticker_symbol}')
|
| 99 |
+
latest_forecast = forecast_reversed.iloc[0]
|
| 100 |
+
|
| 101 |
+
# Last Stock Price details with sentiment indicator
|
| 102 |
+
actual_last_price = df["y"].iloc[-1]
|
| 103 |
+
predicted_last_price = latest_forecast['yhat']
|
| 104 |
+
sentiment = determine_sentiment(actual_last_price, predicted_last_price)
|
| 105 |
+
st.warning(f'The last available adjusted closing price for {ticker_symbol} on {end_date.strftime("%d %B %Y")} is **{actual_last_price:.2f}**.')
|
| 106 |
+
|
| 107 |
+
if sentiment == 'Positive':
|
| 108 |
+
st.success(f'Overall predication indicates positive sentiment.')
|
| 109 |
+
elif sentiment == 'Negative':
|
| 110 |
+
st.error(f'Overall predication indicates negative sentiment.')
|
| 111 |
+
else:
|
| 112 |
+
st.info(f'Overall predication indicates neutral sentiment.')
|
| 113 |
+
|
| 114 |
+
# Prediction details
|
| 115 |
+
st.markdown(f"""
|
| 116 |
+
**Prediction for {forecast_horizon.lower()}:**
|
| 117 |
+
|
| 118 |
+
- **Date:** {latest_forecast['ds'].strftime("%d %B %Y")}
|
| 119 |
+
- **Predicted Price:** {latest_forecast['yhat']:.2f}
|
| 120 |
+
- **Lower Bound:** {latest_forecast['yhat_lower']:.2f}
|
| 121 |
+
- **Upper Bound:** {latest_forecast['yhat_upper']:.2f}
|
| 122 |
+
""")
|
| 123 |
+
|
| 124 |
+
st.markdown(f"""
|
| 125 |
+
**Find below the prediction Data for the {forecast_horizon.lower()}:**
|
| 126 |
+
|
| 127 |
+
""")
|
| 128 |
+
st.write(forecast_reversed)
|
| 129 |
+
|
| 130 |
+
|
| 131 |
+
# Calculate performance metrics
|
| 132 |
+
# Function to determine if performance metrics are in a good range
|
| 133 |
+
def evaluate_performance_metrics(metrics):
|
| 134 |
+
evaluation = {}
|
| 135 |
+
evaluation['MAE'] = 'Good' if metrics['MAE'] < 0.05 * (df['y'].max() - df['y'].min()) else 'Not Good'
|
| 136 |
+
evaluation['MSE'] = 'Good' if metrics['MSE'] < 0.1 * (df['y'].max() - df['y'].min())**2 else 'Not Good'
|
| 137 |
+
evaluation['RMSE'] = 'Good' if metrics['RMSE'] < 0.1 * (df['y'].max() - df['y'].min()) else 'Not Good'
|
| 138 |
+
return evaluation
|
| 139 |
+
|
| 140 |
+
# Calculate performance metrics
|
| 141 |
+
actual = df['y']
|
| 142 |
+
predicted = forecast['yhat'][:len(df)]
|
| 143 |
+
metrics = calculate_performance_metrics(actual, predicted)
|
| 144 |
+
|
| 145 |
+
# Evaluate performance metrics
|
| 146 |
+
evaluation = evaluate_performance_metrics(metrics)
|
| 147 |
+
|
| 148 |
+
metrics = calculate_performance_metrics(actual, predicted)
|
| 149 |
+
MAE =metrics['MAE']
|
| 150 |
+
MSE = metrics['MSE']
|
| 151 |
+
RMSE = metrics['RMSE']
|
| 152 |
+
|
| 153 |
+
|
| 154 |
+
# Display evaluation
|
| 155 |
+
st.subheader('Performance Evaluation')
|
| 156 |
+
st.write('The metrics below provide a quantitative measure of the model’s accuracy:')
|
| 157 |
+
maecolor = "green" if evaluation["MAE"] == "Good" else "red"
|
| 158 |
+
msecolor = "green" if evaluation["MSE"] == "Good" else "red"
|
| 159 |
+
rmsecolor = "green" if evaluation["RMSE"] == "Good" else "red"
|
| 160 |
+
|
| 161 |
+
st.markdown(f'- **Mean Absolute Error (MAE):** {MAE:.2f} - :{maecolor}[{"Good" if evaluation["MAE"] == "Good" else "Not good"}] ')
|
| 162 |
+
st.markdown("(The average absolute difference between predicted and actual values.)")
|
| 163 |
+
|
| 164 |
+
st.markdown(f'- **Mean Squared Error (MSE):** {MSE:.2f} - :{msecolor}[{"Good" if evaluation["MSE"] == "Good" else "Not good"}] ')
|
| 165 |
+
st.markdown("(The average squared difference between predicted and actual values.)")
|
| 166 |
+
|
| 167 |
+
st.markdown(f'- **Root Mean Squared Error (RMSE):** {RMSE:.2f} - :{rmsecolor}[{"Good" if evaluation["RMSE"] == "Good" else "Not good"}] ')
|
| 168 |
+
st.markdown("(The square root of MSE, which is more interpretable in the same units as the target variable.)")
|
| 169 |
+
|
| 170 |
+
|
| 171 |
+
|
| 172 |
+
|
| 173 |
+
|
| 174 |
+
# Run the main function
|
| 175 |
+
if __name__ == "__main__":
|
| 176 |
+
main()
|
requirements.txt
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
streamlit
|
| 3 |
+
pandas
|
| 4 |
+
yfinance
|
| 5 |
+
prophet
|
| 6 |
+
numpy
|
| 7 |
+
matplotlib
|
| 8 |
+
plotly
|
| 9 |
+
scikit-learn
|