|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import os |
|
import joblib |
|
import yfinance as yf |
|
import pandas as pd |
|
import numpy as np |
|
from datetime import datetime |
|
from sklearn.metrics import mean_absolute_percentage_error |
|
from sklearn.linear_model import LinearRegression |
|
import gradio as gr |
|
|
|
|
|
Stock = "NVDA" |
|
model_path = f"./model/{Stock}_lr_model.pkl" |
|
start_date = "2020-01-01" |
|
test_start_date = "2025-01-01" |
|
today = datetime.today().strftime('%Y-%m-%d') |
|
|
|
|
|
if not os.path.exists(model_path): |
|
raise FileNotFoundError(f"Model not found at {model_path}. Please train and save it first.") |
|
|
|
model = joblib.load(model_path) |
|
|
|
def run_prediction(): |
|
|
|
data = yf.download(Stock, start=start_date, end=today)[["Close"]] |
|
data.dropna(inplace=True) |
|
data.index = pd.to_datetime(data.index) |
|
|
|
|
|
xactual = data[:-1]["Close"].values.reshape(-1, 1) |
|
ytrue = data[1:]["Close"] |
|
dates = data[1:].index |
|
|
|
|
|
mask = dates >= test_start_date |
|
xactual = xactual[mask] |
|
ytrue = ytrue[mask] |
|
dates = dates[mask] |
|
|
|
|
|
typred = model.predict(xactual) |
|
|
|
|
|
pred_df = pd.DataFrame({ |
|
"Date": dates, |
|
"Actual Close": ytrue.squeeze().values, |
|
"Predicted Close": typred.flatten() |
|
}) |
|
|
|
|
|
pred_df["% Error Raw"] = ((pred_df["Predicted Close"] - pred_df["Actual Close"]) / pred_df["Actual Close"]) * 100 |
|
|
|
|
|
mape = np.mean(np.abs(pred_df["% Error Raw"])) |
|
sape = np.std(np.abs(pred_df["% Error Raw"])) |
|
|
|
|
|
pred_df["Actual Close"] = pred_df["Actual Close"].round(2) |
|
pred_df["Predicted Close"] = pred_df["Predicted Close"].round(2) |
|
pred_df["% Error"] = pred_df["% Error Raw"].apply(lambda x: f"$ {x:+.2f}") |
|
pred_df.drop(columns=["% Error Raw"], inplace=True) |
|
|
|
|
|
pred_df["±MAPE Range"] = pred_df["Predicted Close"].apply( |
|
lambda x: f"${x * (1 - mape/100):.2f} to ${x * (1 + mape/100):.2f}" |
|
) |
|
|
|
|
|
|
|
latest_close = float(data["Close"].iloc[-1]) |
|
latest_date = data.index[-1].strftime("%Y-%m-%d") |
|
next_pred = float(model.predict(np.array([[latest_close]]))[0]) |
|
next_date = (data.index[-1] + pd.tseries.offsets.BDay(1)).strftime("%Y-%m-%d") |
|
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S") |
|
|
|
|
|
mape_range = (next_pred * (1 - mape/100), next_pred * (1 + mape/100)) |
|
sape_range = (next_pred * (1 - sape/100), next_pred * (1 + sape/100)) |
|
|
|
summary = f""" |
|
Prediction for {Stock} made at {now}: |
|
Last available date: {latest_date}, Close = ${latest_close:.2f} |
|
Predicted closing price for next trading day ({next_date}): ${next_pred:.2f} |
|
Expected range (±MAPE): ${mape_range[0]:.2f} to ${mape_range[1]:.2f} |
|
Expected range (±SAPE): ${sape_range[0]:.2f} to ${sape_range[1]:.2f} |
|
""" |
|
|
|
|
|
pred_df = pred_df.sort_values("Date", ascending=False) |
|
pred_df["Date"] = pred_df["Date"].dt.strftime("%Y-%m-%d") |
|
|
|
return summary, pred_df |
|
|
|
|
|
description = f"""<h3>Linear Regression Stock Prediction</h3> |
|
<p>This app loads a trained linear regression model for <b>{Stock}</b> and predicts the next trading day's close based on the last available price. |
|
It also shows historical prediction accuracy from 2025 onward.</p>""" |
|
|
|
demo = gr.Interface( |
|
fn=run_prediction, |
|
inputs=[], |
|
outputs=[ |
|
gr.Textbox(label="Prediction Summary", lines=6), |
|
gr.Dataframe(label="Prediction Table (2025+)", wrap=True) |
|
], |
|
title="Stock Prediction using Linear Regression", |
|
description=description, |
|
allow_flagging="never" |
|
) |
|
|
|
if __name__ == "__main__": |
|
demo.launch() |
|
|