prakashkota commited on
Commit
b30a615
·
1 Parent(s): d01f438

initial project files

Browse files
.DS_Store ADDED
Binary file (6.15 kB). View file
 
app.py ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #+--------------------------------------------------------------------------------------------+
2
+ # Model for Stock Price Prediction via Dense only Neural Network
3
+ # Using today vs tomorrow analysis
4
+ #
5
+ # Written by: Prakash R. Kota
6
+ # Location: East Greenbush, NY
7
+ #
8
+ # Using just a Dense Neural Network Model
9
+ # Adding lots of direct stock parmeters from Yahoo Finance
10
+ # Open, High, Low, Close, Volume
11
+ #
12
+ # Will not be using other parameters such as
13
+ # Return, SMA10, EMA10, RollingVol10,
14
+ # SP500, Nasdaq, VIX
15
+ # RSI, Day-of-Week
16
+ # Removed all saving and graphing from PRK_1a_tf_Stock_NN.ipnyb
17
+ # Keeping it minimal for just the stock prediction and output display table
18
+ # Goal is to make a MVP - Minimal Viable Product
19
+ # Infer the NN Model from the Saved Model - app.py required for Hugging Face Space
20
+ #
21
+ # PRK_1b_2_Model_Infer_tf_Stock_NN.ipnyb - Using Tensorflow 2.16.2 CPU
22
+ # based on
23
+ # PRK_1b_tf_Stock_NN.ipnyb
24
+ # PRK_1a_tf_Stock_NN.ipnyb
25
+ # PRK_11b_tf_Stock_DenseOnly.ipynb
26
+ # Renamed PRK_10e_tf_Stock_DenseOnly.ipynb for convenience
27
+ # This is the best Notebook Code for the NN Model
28
+ #
29
+ # Written on: 28 Mar 2025
30
+ # Last update: 29 Mar 2025
31
+ #+--------------------------------------------------------------------------------------------+
32
+
33
+ import gradio as gr
34
+ import numpy as np
35
+ import pandas as pd
36
+ import yfinance as yf
37
+ from datetime import datetime
38
+ from pandas.tseries.offsets import BDay
39
+ from tabulate import tabulate
40
+ import os
41
+
42
+ from tensorflow.keras.models import load_model
43
+ from sklearn.preprocessing import MinMaxScaler
44
+ import joblib
45
+
46
+ import sklearn
47
+ import tensorflow as tf
48
+ import shutil
49
+ from pytz import timezone
50
+ from pandas.tseries.offsets import BDay
51
+ import hashlib
52
+
53
+ # --- Load saved model and scalers --- #
54
+ model_dir = "./model"
55
+ # import os
56
+ # model_dir = os.path.join(os.path.dirname(__file__), "model")
57
+
58
+ NN_model = load_model(os.path.join(model_dir, "NN_CPU_model.keras"))
59
+
60
+ NN_model.compile(optimizer="adam", loss="mse") # even if not used, ensures full init
61
+ NN_model.predict(np.zeros((1, 5))) # warm-up dummy prediction
62
+
63
+ scaler_X = joblib.load(os.path.join(model_dir, "scaler_X.pkl"))
64
+ scaler_y = joblib.load(os.path.join(model_dir, "scaler_y.pkl"))
65
+
66
+ # --- Inference Function --- #
67
+ def predict_stock():
68
+
69
+ # --- Clear yfinance cache to get latest volume and price data --- #
70
+ cache_path = os.path.expanduser("~/.cache/py-yfinance")
71
+ if os.path.exists(cache_path):
72
+ print("Clearing yfinance cache...")
73
+ shutil.rmtree(cache_path)
74
+
75
+ Stock = "NVDA"
76
+ start_date = "2020-01-01"
77
+ train_end_date = "2024-12-31"
78
+ today = datetime.today().strftime('%Y-%m-%d')
79
+
80
+ # Download the full dataset (might contain stale final row)
81
+ try:
82
+ full_data = yf.download(
83
+ tickers=Stock,
84
+ start=start_date,
85
+ end=today,
86
+ interval="1d",
87
+ auto_adjust=False,
88
+ actions=False,
89
+ progress=False,
90
+ threads=False
91
+ )
92
+ if full_data.empty:
93
+ raise RuntimeError("Download failed or returned no data.")
94
+ except Exception as e:
95
+ print("yfinance error:", e)
96
+ return "Error: Could not fetch stock data. Please try again later.", pd.DataFrame()
97
+
98
+ features = ["Open", "High", "Low", "Close", "Volume"]
99
+
100
+ X_scaled = scaler_X.transform(full_data[features])
101
+ y = full_data["Close"].values.reshape(-1, 1)
102
+ y_scaled = scaler_y.transform(y)
103
+
104
+ X_all = X_scaled[:-1]
105
+ y_all = y_scaled[1:].flatten()
106
+ dates_all = full_data.index[1:]
107
+
108
+ test_mask = dates_all > pd.to_datetime(train_end_date)
109
+ X_test, y_test = X_all[test_mask], y_all[test_mask]
110
+ dates_test = dates_all[test_mask]
111
+
112
+ # Predict next day prices
113
+ y_pred_scaled = NN_model.predict(X_test).flatten()
114
+ y_pred = scaler_y.inverse_transform(y_pred_scaled.reshape(-1, 1)).flatten()
115
+ y_true = scaler_y.inverse_transform(y_test.reshape(-1, 1)).flatten()
116
+
117
+ last_date = full_data.index[-1]
118
+ last_close_price = float(full_data["Close"].iloc[-1].item())
119
+ X_input = X_scaled[-1].reshape(1, -1)
120
+
121
+ next_day_pred_scaled = NN_model.predict(X_input)
122
+ next_day_pred = scaler_y.inverse_transform(next_day_pred_scaled)[0][0]
123
+
124
+ mape = np.mean(np.abs((y_true - y_pred) / y_true)) * 100
125
+ std_ape = np.std(np.abs((y_true - y_pred) / y_true)) * 100
126
+
127
+ mape_margin = next_day_pred * (mape / 100)
128
+ sae_margin = next_day_pred * (std_ape / 100)
129
+
130
+ next_date = (last_date + BDay(1)).date()
131
+
132
+ summary_lines = [
133
+ f"Prediction for {Stock}:",
134
+ f"Last available date: {last_date.date()}, Close = ${last_close_price:.2f}",
135
+ f"Predicted closing price for next trading day ({next_date}): ${next_day_pred:.2f}",
136
+ f"Expected range (±MAPE): ${next_day_pred - mape_margin:.2f} to ${next_day_pred + mape_margin:.2f}",
137
+ f"Expected range (±SAE): ${next_day_pred - sae_margin:.2f} to ${next_day_pred + sae_margin:.2f}"
138
+ ]
139
+ summary = "\n".join(summary_lines)
140
+
141
+ prediction_df = pd.DataFrame({
142
+ 'Date': dates_test,
143
+ 'Actual Close': y_true,
144
+ 'Predicted Close': y_pred
145
+ })
146
+
147
+ prediction_df['% Error'] = ((prediction_df['Actual Close'] - prediction_df['Predicted Close']) / prediction_df['Actual Close']) * 100
148
+ prediction_df['% Error'] = prediction_df['% Error'].map(lambda x: f"{x:+.2f}%")
149
+ prediction_df['±MAPE Range'] = prediction_df['Predicted Close'].apply(
150
+ lambda x: f"${x * (1 - mape/100):.2f} to ${x * (1 + mape/100):.2f}"
151
+ )
152
+
153
+ prediction_df['Date'] = prediction_df['Date'].dt.strftime("%Y-%m-%d")
154
+ prediction_df['Actual Close'] = prediction_df['Actual Close'].map(lambda x: f"${x:.2f}")
155
+ prediction_df['Predicted Close'] = prediction_df['Predicted Close'].map(lambda x: f"${x:.2f}")
156
+ prediction_df = prediction_df.sort_values("Date", ascending=False)
157
+
158
+ headers = ["Prediction For Date", "Actual Close", "Predicted Close", "% Error", "±MAPE Range"]
159
+ table = tabulate(prediction_df.values, headers=headers, tablefmt="plain")
160
+
161
+ """
162
+ # Start Sanity Checks
163
+ assert not np.any(np.isnan(X_scaled[-1].reshape(1, -1))), "NaNs detected in input!"
164
+ assert X_scaled[-1].reshape(1, -1).shape == (1, X_scaled.shape[1]), f"Unexpected shape: {X_scaled[-1].reshape(1, -1).shape}"
165
+ print("X_input shape:", X_scaled[-1].reshape(1, -1).shape)
166
+ print("X_input contains NaNs:", np.any(np.isnan(X_scaled[-1].reshape(1, -1))))
167
+
168
+ print("Latest data row used for prediction:")
169
+ print(full_data[features].iloc[-1])
170
+
171
+ print("scikit-learn version:", sklearn.__version__)
172
+ print("tensorflow version:", tf.__version__)
173
+ print("scaler_X min/max:", scaler_X.data_min_, scaler_X.data_max_)
174
+ print("scaler_y min/max:", scaler_y.data_min_, scaler_y.data_max_)
175
+
176
+ # Run a prediction on a known fixed input
177
+ x_debug = np.array([[0.5, 0.5, 0.5, 0.5, 0.5]])
178
+ y_debug = NN_model.predict(x_debug)
179
+ y_debug_unscaled = scaler_y.inverse_transform(y_debug)
180
+ print("Debug prediction (scaled):", y_debug)
181
+ print("Debug prediction (unscaled):", y_debug_unscaled)
182
+
183
+ import hashlib
184
+
185
+ def md5(fname):
186
+ with open(fname, "rb") as f:
187
+ return hashlib.md5(f.read()).hexdigest()
188
+
189
+ #print("Model MD5 checksum:", md5(os.path.join(model_dir, "NN_CPU_model.keras")))
190
+
191
+ print(full_data.tail(3))
192
+
193
+ # End Sanitiy Checks"
194
+ """
195
+
196
+ return summary, prediction_df[["Date", "Actual Close", "Predicted Close", "% Error", "±MAPE Range"]]
197
+
198
+
199
+
200
+ # --- Gradio Interface --- #
201
+ demo = gr.Interface(
202
+ fn=predict_stock,
203
+ inputs=[],
204
+ outputs=[
205
+ gr.Textbox(label="Prediction Summary", lines=6),
206
+ gr.Dataframe(headers=["Prediction For Date", "Actual Close", "Predicted Close", "% Error", "±MAPE Range"], label="Prediction Table (2025+)")
207
+ ],
208
+ title="📈 NVDA Stock Predictor",
209
+ description="This app uses a Dense Neural Network to predict NVDA's next trading day's closing price.",
210
+ live=False
211
+ )
212
+
213
+ demo.launch(share=True)
model/NN_CPU_model.keras ADDED
Binary file (55.3 kB). View file
 
model/scaler_X.pkl ADDED
Binary file (879 Bytes). View file
 
model/scaler_y.pkl ADDED
Binary file (719 Bytes). View file
 
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ gradio==5.23.1
2
+ numpy==1.26.4
3
+ pandas==2.2.3
4
+ yfinance==0.2.55
5
+ tabulate==0.9.0
6
+ tensorflow==2.16.2
7
+ scikit-learn==1.6.1
8
+ joblib==1.4.2
9
+ pytz==2025.1