Nrup Parikh commited on
Commit
b33ff8e
·
1 Parent(s): 7a7ede6

Add application file

Browse files
Files changed (3) hide show
  1. Dockerfile +16 -0
  2. app.py +247 -0
  3. requirements.txt +17 -0
Dockerfile ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Read the doc: https://huggingface.co/docs/hub/spaces-sdks-docker
2
+ # you will also find guides on how best to write your Dockerfile
3
+
4
+ FROM python:3.9
5
+
6
+ RUN useradd -m -u 1000 user
7
+ USER user
8
+ ENV PATH="/home/user/.local/bin:$PATH"
9
+
10
+ WORKDIR /app
11
+
12
+ COPY --chown=user ./requirements.txt requirements.txt
13
+ RUN pip install --no-cache-dir --upgrade -r requirements.txt
14
+
15
+ COPY --chown=user . /app
16
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
app.py ADDED
@@ -0,0 +1,247 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import yfinance as yf
2
+ from datetime import datetime, timedelta
3
+ from sklearn.ensemble import RandomForestRegressor
4
+ from sklearn.model_selection import train_test_split
5
+ from sklearn.metrics import mean_absolute_error
6
+ from flask import Flask, request, render_template_string
7
+
8
+ # Create a Flask application instance
9
+ app = Flask(__name__)
10
+
11
+
12
+ # =============== Data Fetching ===============
13
+ def fetch_stock_data(symbol, period="5y"):
14
+ """Fetch historical stock data from Yahoo Finance"""
15
+ stock = yf.Ticker(symbol)
16
+ data = stock.history(period=period)
17
+ data = data.sort_index(ascending=True)
18
+ return data
19
+
20
+
21
+ # =============== Technical Indicators ===============
22
+ def calculate_moving_averages(data):
23
+ data["50MA"] = data["Close"].rolling(window=50).mean()
24
+ data["200MA"] = data["Close"].rolling(window=200).mean()
25
+ return data
26
+
27
+
28
+ def determin_trend(data):
29
+ if (
30
+ data["50MA"].iloc[-1] > data["200MA"].iloc[-1]
31
+ and data["Close"].iloc[-1] > data["50MA"].iloc[-1]
32
+ ):
33
+ trend = "UPTREND (bullish for next 1-3 months)"
34
+ elif (
35
+ data["50MA"].iloc[-1] < data["200MA"].iloc[-1]
36
+ and data["Close"].iloc[-1] < data["50MA"].iloc[-1]
37
+ ):
38
+ trend = "DOWNTREND (bearish for next 1-3 months)"
39
+ else:
40
+ trend = "SIDEWAYS (uncertain)"
41
+ return trend
42
+
43
+
44
+ def calculate_RSI(data, window=14):
45
+ delta = data["Close"].diff()
46
+ gain = delta.where(delta > 0, 0)
47
+ loss = -delta.where(delta < 0, 0)
48
+ avg_gain = gain.rolling(window=window).mean()
49
+ avg_loss = loss.rolling(window=window).mean()
50
+ rs = avg_gain / avg_loss
51
+ data["RSI"] = 100 - (100 / (1 + rs))
52
+ return data
53
+
54
+
55
+ def calculate_MACD(data, fast=12, slow=26, signal=9):
56
+ data["EMA_fast"] = data["Close"].ewm(span=fast, adjust=False).mean()
57
+ data["EMA_slow"] = data["Close"].ewm(span=slow, adjust=False).mean()
58
+ data["MACD"] = data["EMA_fast"] - data["EMA_slow"]
59
+ data["MACD_signal"] = data["MACD"].ewm(span=signal, adjust=False).mean()
60
+ return data
61
+
62
+
63
+ # =============== Random Forest Forecast ===============
64
+ """
65
+ This function uses a Random Forest ML model to learn from
66
+ historical stock indicators and predict stock prices for the next 30 days.
67
+ """
68
+
69
+
70
+ def random_forest_forecast(data, days_ahead=30):
71
+ """
72
+ Predict future stock prices using Random Forest Regressor
73
+ """
74
+ df = data.copy()
75
+ # next-day close as target
76
+ df["Target"] = df["Close"].shift(-1)
77
+ # Drop last row with NaN target
78
+ df = df.dropna()
79
+ # Features (you can add more indicators here)
80
+ features = ["Close", "50MA", "200MA", "RSI", "MACD", "MACD_signal"]
81
+ # drop rows with NaN from indicators
82
+ df = df.dropna()
83
+ # Feature matrix and target vector
84
+ X = df[features]
85
+ y = df["Target"]
86
+
87
+ # Train/test split
88
+ X_train, X_test, y_train, y_test = train_test_split(
89
+ X, y, test_size=0.2, shuffle=False
90
+ )
91
+
92
+ # Train model
93
+ model = RandomForestRegressor(n_estimators=200, random_state=42)
94
+ model.fit(X_train, y_train)
95
+
96
+ # Evaluate
97
+ y_pred = model.predict(X_test)
98
+ mae = mean_absolute_error(y_test, y_pred)
99
+ print(f"Random Forest MAE: {mae:.2f}")
100
+
101
+ # Forecast future price iteratively
102
+ last_known = X.iloc[-1].values.reshape(1, -1)
103
+ forecast_prices = []
104
+ for _ in range(days_ahead):
105
+ pred = model.predict(last_known)[0]
106
+ forecast_prices.append(pred)
107
+ # update only Close for simplicity
108
+ last_known[0, 0] = pred
109
+
110
+ return forecast_prices[-1], forecast_prices
111
+
112
+
113
+ # =============== Entry / Stoploss ===============
114
+ def calculate_entry_stoploss(data, trend, stoploss_percent=5):
115
+ entry_price = None
116
+ stop_loss = None
117
+ if (
118
+ trend.startswith("UPTREND")
119
+ and data["RSI"].iloc[-1] < 70
120
+ and data["MACD"].iloc[-1] > data["MACD_signal"].iloc[-1]
121
+ ):
122
+ entry_price = data["Close"].iloc[-1]
123
+ stop_loss = entry_price * (1 - stoploss_percent / 100)
124
+ return entry_price, stop_loss
125
+
126
+
127
+ # =============== Flask Routes ===============
128
+ @app.route("/", methods=["GET", "POST"])
129
+ def index():
130
+ stocks = {
131
+ "Reliance Industries": "RELIANCE.NS",
132
+ "Infosys": "INFY.NS",
133
+ "TCS": "TCS.NS",
134
+ "HDFC Bank": "HDFCBANK.NS",
135
+ "Ola Electric": "OLAELEC.NS",
136
+ }
137
+
138
+ result = None
139
+ table_html = None
140
+
141
+ if request.method == "POST":
142
+ selected_symbol = request.form["symbol"]
143
+ data = fetch_stock_data(selected_symbol)
144
+ data = calculate_moving_averages(data)
145
+ data = calculate_RSI(data)
146
+ data = calculate_MACD(data)
147
+ trend = determin_trend(data)
148
+ # Random Forest Forecast
149
+ predicted_price, _ = random_forest_forecast(data)
150
+ # Entry & Stoploss
151
+ entry_price, stop_loss = calculate_entry_stoploss(data, trend)
152
+ current_price = data["Close"].iloc[-1]
153
+ price_difference = predicted_price - current_price
154
+ profit_or_loss = ((predicted_price - current_price) / current_price) * 100
155
+
156
+ table_html = (
157
+ data.tail(30)
158
+ .reset_index()
159
+ .to_html(classes="table table-striped table-bordered", index=False)
160
+ )
161
+
162
+ result = {
163
+ "symbol": selected_symbol,
164
+ "trend": trend,
165
+ "current_price": f"{current_price:.2f}",
166
+ "predicted_price": f"{predicted_price:.2f}",
167
+ "price_difference": f"{price_difference:.2f}",
168
+ "profit_or_loss": f"{profit_or_loss:.2f}%",
169
+ "entry_price": f"{entry_price:.2f}" if entry_price else "No Entry Signal",
170
+ "stop_loss": f"{stop_loss:.2f}" if stop_loss else "-",
171
+ "date_now": data.index[-1].date(),
172
+ "future_date": datetime.now().date() + timedelta(days=30),
173
+ }
174
+
175
+ return render_template_string(
176
+ """
177
+ <html>
178
+ <head>
179
+ <title>Stock Predictor</title>
180
+ <link rel="stylesheet"
181
+ href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css">
182
+ <style>
183
+ body { padding: 30px; }
184
+ th, td { text-align: center; }
185
+ .result-card { margin-top: 40px; }
186
+ </style>
187
+ </head>
188
+ <body>
189
+ <div class="container">
190
+ <h3 class="text-center mb-4">Stock Prediction Dashboard</h3>
191
+ <form method="POST" class="text-center mb-4">
192
+ <div class="row justify-content-center">
193
+ <div class="col-md-4">
194
+ <select name="symbol" class="form-select">
195
+ {% for name, sym in stocks.items() %}
196
+ <option value="{{ sym }}"
197
+ {% if result and result.symbol == sym %}selected{% endif %}>
198
+ {{ name }} ({{ sym }})
199
+ </option>
200
+ {% endfor %}
201
+ </select>
202
+ </div>
203
+ <div class="col-md-2">
204
+ <button type="submit" class="btn btn-primary w-100">Predict</button>
205
+ </div>
206
+ </div>
207
+ </form>
208
+
209
+ {% if result %}
210
+ <div class="card result-card shadow">
211
+ <div class="card-body">
212
+ <h5 class="card-title text-center">Report for {{ result.symbol }}</h5>
213
+ <p><b>Trend:</b> {{ result.trend }}</p>
214
+ <p><b>Current Price:</b> ₹{{ result.current_price }} ({{ result.date_now }})</p>
215
+ <p><b>Predicted Price (Next 30 Days):</b> ₹{{ result.predicted_price }} ({{ result.future_date }})</p>
216
+ <p><b>Price Difference:</b> ₹{{ result.price_difference }}</p>
217
+ <p><b>Expected Return:</b> {{ result.profit_or_loss }}</p>
218
+ <p><b>Entry Price:</b> {{ result.entry_price }}</p>
219
+ <p><b>Stop Loss:</b> {{ result.stop_loss }}</p>
220
+ </div>
221
+ </div>
222
+
223
+ <div class="mt-4">
224
+ <h5>Last 30 Days Data</h5>
225
+ {{ table_html | safe }}
226
+ </div>
227
+ {% endif %}
228
+ </div>
229
+ </body>
230
+ </html>
231
+ """,
232
+ stocks=stocks,
233
+ result=result,
234
+ table_html=table_html,
235
+ )
236
+
237
+
238
+ # Run the app in debug mode
239
+ if __name__ == "__main__":
240
+ # Run on local host
241
+ # app.run(debug=True)
242
+
243
+ # Run using public IP
244
+ # app.run(host="0.0.0.0", port=5000, debug=True)
245
+
246
+ # Hugging Face uses port 7860 by default
247
+ app.run(host="0.0.0.0", port=7860)
requirements.txt ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Web Framework: The lightweight framework for building the application structure (routes, views, etc.)
2
+ flask
3
+
4
+ # Production Server: A critical component for deployment. Used by Docker to serve the Flask app live on Hugging Face Spaces.
5
+ gunicorn
6
+
7
+ # Data Acquisition: Used to download historical stock data from Yahoo Finance.
8
+ yfinance
9
+
10
+ # Machine Learning: The library containing the Random Forest algorithm for making predictions.
11
+ scikit-learn
12
+
13
+ # Data Processing: Used for handling data structures like DataFrames, essential for cleaning, manipulating, and preparing stock data.
14
+ pandas
15
+
16
+ # Scientific Computing: Provides high-performance array and mathematical operations, often used internally by pandas and scikit-learn.
17
+ numpy