Spaces:
Sleeping
Sleeping
import yfinance as yf | |
import pandas as pd | |
import numpy as np | |
from sklearn.ensemble import RandomForestRegressor | |
from sklearn.metrics import mean_squared_error | |
from sklearn.model_selection import train_test_split | |
import gradio as gr | |
import matplotlib.pyplot as plt | |
from datetime import datetime, timedelta | |
# Define stock tickers | |
STOCK_TICKERS = [ | |
"AAPL", # Apple | |
"GOOGL", # Alphabet | |
"MSFT", # Microsoft | |
"AMZN", # Amazon | |
"TSLA", # Tesla | |
"META", # Meta Platforms | |
"NVDA", # NVIDIA | |
"JPM", # JPMorgan Chase | |
"V", # Visa | |
"NFLX" # Netflix | |
] | |
def fetch_stock_data(ticker: str, start_date: str, end_date: str) -> pd.DataFrame: | |
""" | |
Fetches historical stock data from Yahoo Finance. | |
""" | |
stock = yf.Ticker(ticker) | |
data = stock.history(start=start_date, end=end_date) | |
return data | |
def preprocess_data(data: pd.DataFrame) -> (np.ndarray, np.ndarray): | |
""" | |
Preprocesses the stock data for Random Forest Regressor. | |
""" | |
data['Target'] = data['Close'].shift(-1) # Predict next day's close price | |
data = data[:-1] | |
# Create features using the previous 5 days' close prices | |
for i in range(1, 6): | |
data[f'Close_{i}'] = data['Close'].shift(i) | |
data.dropna(inplace=True) | |
X = data[[f'Close_{i}' for i in range(1, 6)]].values | |
y = data['Target'].values | |
return X, y | |
def train_model(X: np.ndarray, y: np.ndarray) -> RandomForestRegressor: | |
""" | |
Trains the Random Forest Regressor model. | |
""" | |
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=False) | |
model = RandomForestRegressor(n_estimators=100, random_state=42) | |
model.fit(X_train, y_train) | |
predictions = model.predict(X_test) | |
mse = mean_squared_error(y_test, predictions) | |
print(f"Model Mean Squared Error: {mse}") | |
return model | |
def make_prediction(model: RandomForestRegressor, recent_data: pd.DataFrame, days: int) -> np.ndarray: | |
""" | |
Makes predictions for the next 'days' closing prices. | |
""" | |
predicted_prices = [] | |
last_close = recent_data['Close'].values[-5:] | |
for _ in range(days): | |
if len(last_close) < 5: | |
raise ValueError("Not enough data to make a prediction.") | |
X_new = last_close[::-1].reshape(1, -1) # Reverse to match feature order | |
predicted_price = model.predict(X_new)[0] | |
predicted_prices.append(predicted_price) | |
# Update the last_close with the predicted price for the next iteration | |
last_close = np.roll(last_close, -1) | |
last_close[-1] = predicted_price | |
return predicted_prices | |
def buy_or_sell(current_price: float, predicted_price: float) -> str: | |
""" | |
Determines whether to buy or sell based on price prediction. | |
""" | |
return "Buy" if predicted_price > current_price else "Sell" | |
def stock_prediction_app(ticker: str, start_date: str, end_date: str): | |
""" | |
Main function to handle stock prediction and return outputs. | |
""" | |
data = fetch_stock_data(ticker, start_date, end_date) | |
if data.empty: | |
return "No data available for the selected dates.", "N/A", "N/A", "N/A", "N/A", None | |
# Calculate basic stats | |
current_price = data['Close'].iloc[-1] | |
highest_price = data['Close'].max() | |
lowest_price = data['Close'].min() | |
start_price = data['Close'].iloc[0] | |
percentage_change = ((current_price - start_price) / start_price) * 100 | |
# Preprocess and train model | |
X, y = preprocess_data(data) | |
if len(X) == 0: | |
return "Insufficient data to train the model.", current_price, highest_price, lowest_price, "Error", None | |
model = train_model(X, y) | |
# Predict the next 60 days | |
predicted_prices = make_prediction(model, data, days=60) | |
# Create dates for predictions | |
future_dates = pd.date_range(start=data.index[-1] + timedelta(days=1), periods=60, freq='B') # Business days | |
# Prepare data for plotting | |
plt.figure(figsize=(14, 7)) | |
# Plot historical prices | |
plt.plot(data.index, data['Close'], label='Historical Close Price', color='blue', linewidth=2) | |
# Plot predicted prices | |
plt.plot(future_dates, predicted_prices, label='Predicted Prices', color='orange', linestyle='--', linewidth=2) | |
# Highlight current price | |
plt.axhline(y=current_price, color='green', linestyle='--', label='Current Close Price', linewidth=1.5) | |
# Adding labels and grid for clarity | |
plt.title(f'{ticker} Price Prediction', fontsize=16) | |
plt.xlabel('Date', fontsize=14) | |
plt.ylabel('Price ($)', fontsize=14) | |
plt.xticks(rotation=45) | |
plt.legend() | |
plt.grid() | |
plt.tight_layout() | |
fig = plt.gcf() | |
plt.close() | |
# Format outputs | |
percentage_change_str = f"{percentage_change:.2f}%" | |
decision = buy_or_sell(current_price, predicted_prices[0]) # Decision based on the first predicted price | |
return percentage_change_str, current_price, highest_price, lowest_price, decision, fig | |
# Gradio interface setup | |
iface = gr.Interface( | |
fn=stock_prediction_app, | |
inputs=[ | |
gr.Dropdown(choices=STOCK_TICKERS, label="Select Stock Ticker"), | |
gr.Textbox(label="Enter Start Date (YYYY-MM-DD)", placeholder="e.g., 2020-01-01"), | |
gr.Textbox(label="Enter End Date (YYYY-MM-DD)", placeholder="e.g., 2023-12-31") | |
], | |
outputs=[ | |
gr.Textbox(label="Percentage Change"), | |
gr.Number(label="Current Closing Price"), | |
gr.Number(label="Highest Closing Price"), | |
gr.Number(label="Lowest Closing Price"), | |
gr.Textbox(label="Decision (Buy/Sell)"), | |
gr.Plot(label="Stock Performance") | |
], | |
title="Stock Prediction App", | |
description="Predict stock trends using historical data. Please enter dates in the format YYYY-MM-DD." | |
) | |
# Launch the app | |
iface.launch() |