Khelendramee commited on
Commit
2a69bdb
·
verified ·
1 Parent(s): 3d232c0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +94 -87
app.py CHANGED
@@ -1,71 +1,70 @@
1
  from fastapi import FastAPI
2
  from sklearn.preprocessing import MinMaxScaler
3
- from tensorflow.keras.models import Sequential
4
  from tensorflow.keras.layers import LSTM, Dense
5
  import numpy as np
6
- from datetime import datetime, timedelta, time as dtime
7
  import pandas as pd
8
  import yfinance as yf
9
  import pytz
 
 
10
 
11
  app = FastAPI()
12
 
13
- # Create dataset helper
14
- def create_dataset(data, time_step=1, predict_steps=1):
 
 
 
 
15
  X, y = [], []
16
  for i in range(len(data) - time_step - predict_steps):
17
- X.append(data[i:i+time_step])
18
- y.append(data[i+time_step:i+time_step+predict_steps])
19
  return np.array(X), np.array(y)
20
 
21
- def profit_with_short_selling_json(prices, st, im):
 
22
  min_price = prices[0]
23
- buy_time = 0
24
- sell_time = 0
25
  max_profit = 0
26
- trade = []
 
27
 
28
  for i in range(1, len(prices)):
29
  if prices[i] - min_price > max_profit:
30
  max_profit = prices[i] - min_price
31
- sell_time = i
32
- buy_time = prices.tolist().index(min_price)
33
 
34
  if prices[i] < min_price:
35
  min_price = prices[i]
36
 
37
- time_str = "9:15"
38
- time_obj = datetime.strptime(time_str, "%H:%M")
39
- i = time_obj + timedelta(minutes=im + buy_time)
40
- f = time_obj + timedelta(minutes=im + sell_time)
41
 
42
- if buy_time < sell_time:
43
- stock = {
44
- "stock": st,
45
- "price": float(prices[sell_time]),
46
  "change": float(max(prices) - min(prices)),
47
  "prediction": "will rise",
48
  "reason": "The stock is showing positive trends.",
49
- "time": "at 10:00 AM",
50
- "suggestion": f"Buy at {i.strftime('%I:%M %p')}, Sell at {f.strftime('%I:%M %p')}"
51
  }
52
  else:
53
- stock = {
54
- "stock": st,
55
- "price": float(prices[buy_time]),
56
  "change": float(min(prices) - max(prices)),
57
  "prediction": "might fall",
58
  "reason": "Recent market instability affecting the stock.",
59
- "time": "at 10:00 AM",
60
- "suggestion": f"Sell at {f.strftime('%I:%M %p')}, Buy at {i.strftime('%I:%M %p')}"
61
  }
62
 
63
- trade.append(stock)
64
- return trade
65
-
66
- # GET MARKET MINUTES
67
- def get_market_minutes():
68
- now = datetime.now().time()
69
  market_open = dtime(9, 15)
70
  market_close = dtime(15, 30)
71
 
@@ -76,86 +75,94 @@ def get_market_minutes():
76
  open_minutes = market_open.hour * 60 + market_open.minute
77
  return now_minutes - open_minutes
78
 
79
- # TRAIN MODEL
80
- @app.get('/model/train/{symbol}/{p_step}')
81
- def train(symbol: str, p_step: int):
82
- import pytz
83
- import yfinance as yf
84
-
85
- predict_steps = p_step
86
- time_steps = 60
87
- training_period = '5d'
88
- epochs = 206
89
 
90
- tz = pytz.timezone('Asia/Kolkata')
91
- now = datetime.now(tz)
92
- today = now.date()
 
93
 
94
- data = yf.download(tickers=symbol, interval='1m', period=training_period, progress=False)
95
  if data.empty:
96
- return {"error": "No data received from Yahoo Finance. Try another symbol or interval."}
97
 
98
- data = data.tz_convert('Asia/Kolkata')
99
  data['Date'] = data.index.date
100
- available_dates = sorted(list(set(data['Date'])))
101
- if today not in available_dates:
102
- if not available_dates:
103
- return {"error": "No available trading dates in the data."}
104
- today = available_dates[-1]
105
-
106
  data_today = data[data['Date'] == today].between_time("09:15", "15:30")
107
  data_train = data[data['Date'] < today]
108
 
109
  if data_train.empty or data_today.empty:
110
- return {"error": "Not enough data."}
111
 
112
- prices = data_train[['Close']]
113
  scaler = MinMaxScaler()
114
- scaled_prices = scaler.fit_transform(prices)
115
 
116
- X, y = create_dataset(scaled_prices, time_steps, predict_steps)
117
  X = X.reshape(X.shape[0], X.shape[1], 1)
118
 
119
- # Create and train a new model per request
120
  model = Sequential()
121
- model.add(LSTM(50, return_sequences=False, input_shape=(time_steps, 1)))
122
- model.add(Dense(predict_steps))
123
  model.compile(loss='mean_squared_error', optimizer='adam')
124
- model.fit(X, y, epochs=epochs, batch_size=32, verbose=1)
125
 
126
- # Save to global for prediction use
127
- app.state.model = model
128
- app.state.scaler = scaler
129
- app.state.data_today = data_today
 
130
 
131
- return {"status": "model trained"}
132
 
133
- # PREDICT
134
  @app.get("/predict/{symbol}")
135
- def predict_view(symbol: str):
136
- time_step = 60
 
137
 
138
- if not hasattr(app.state, "model"):
139
- return {"error": "Model not trained yet."}
140
 
141
- latest = app.state.data_today[['Close']].tail(time_step)
142
- if len(latest) < time_step:
143
- return {"error": "Not enough data for prediction."}
 
 
144
 
145
- scaler = app.state.scaler
146
- scaler.fit(latest)
147
- latest_scaled = scaler.transform(latest)
148
- latest_input = latest_scaled.reshape(1, time_step, 1)
149
 
150
- predicted_scaled = app.state.model.predict(latest_input)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
  predicted_prices = scaler.inverse_transform(predicted_scaled.reshape(-1, 1)).flatten()
152
 
153
- im = get_market_minutes()
154
- predictions = profit_with_short_selling_json(predicted_prices, symbol, im)[0]
155
 
156
  return {
157
- "predictions": predictions,
158
- "timestamp": f"{datetime.now()}",
159
- "predicted_values": predicted_prices.tolist()
 
160
  }
161
-
 
1
  from fastapi import FastAPI
2
  from sklearn.preprocessing import MinMaxScaler
3
+ from tensorflow.keras.models import Sequential, load_model
4
  from tensorflow.keras.layers import LSTM, Dense
5
  import numpy as np
6
+ from datetime import datetime, time as dtime
7
  import pandas as pd
8
  import yfinance as yf
9
  import pytz
10
+ import os
11
+ import joblib
12
 
13
  app = FastAPI()
14
 
15
+ # Paths for saving models and scalers
16
+ MODEL_DIR = "saved_models"
17
+ os.makedirs(MODEL_DIR, exist_ok=True)
18
+
19
+ # Helper: Create dataset for LSTM
20
+ def create_dataset(data, time_step=60, predict_steps=5):
21
  X, y = [], []
22
  for i in range(len(data) - time_step - predict_steps):
23
+ X.append(data[i:i + time_step])
24
+ y.append(data[i + time_step:i + time_step + predict_steps])
25
  return np.array(X), np.array(y)
26
 
27
+ # Helper: Predict Buy/Sell timing with real timestamps
28
+ def profit_with_short_selling_json(prices, timestamps, symbol):
29
  min_price = prices[0]
 
 
30
  max_profit = 0
31
+ buy_idx = 0
32
+ sell_idx = 0
33
 
34
  for i in range(1, len(prices)):
35
  if prices[i] - min_price > max_profit:
36
  max_profit = prices[i] - min_price
37
+ sell_idx = i
38
+ buy_idx = prices.tolist().index(min_price)
39
 
40
  if prices[i] < min_price:
41
  min_price = prices[i]
42
 
43
+ buy_time = timestamps[buy_idx].strftime('%I:%M %p')
44
+ sell_time = timestamps[sell_idx].strftime('%I:%M %p')
 
 
45
 
46
+ if buy_idx < sell_idx:
47
+ return {
48
+ "stock": symbol,
49
+ "price": float(prices[sell_idx]),
50
  "change": float(max(prices) - min(prices)),
51
  "prediction": "will rise",
52
  "reason": "The stock is showing positive trends.",
53
+ "suggestion": f"Buy at {buy_time}, Sell at {sell_time}"
 
54
  }
55
  else:
56
+ return {
57
+ "stock": symbol,
58
+ "price": float(prices[buy_idx]),
59
  "change": float(min(prices) - max(prices)),
60
  "prediction": "might fall",
61
  "reason": "Recent market instability affecting the stock.",
62
+ "suggestion": f"Sell at {sell_time}, Buy at {buy_time}"
 
63
  }
64
 
65
+ # Helper: Get time in market minutes (India default)
66
+ def get_market_minutes(market_tz='Asia/Kolkata'):
67
+ now = datetime.now(pytz.timezone(market_tz)).time()
 
 
 
68
  market_open = dtime(9, 15)
69
  market_close = dtime(15, 30)
70
 
 
75
  open_minutes = market_open.hour * 60 + market_open.minute
76
  return now_minutes - open_minutes
77
 
78
+ # Train model endpoint
79
+ @app.get("/model/train/{symbol}")
80
+ def train_model(symbol: str, time_step: int = 60, p_step: int = 5):
81
+ training_period = "5d"
82
+ epochs = 100
83
+ batch_size = 32
 
 
 
 
84
 
85
+ stock_info = yf.Ticker(symbol).info
86
+ tz_name = stock_info.get('exchangeTimezoneName', 'UTC')
87
+ tz = pytz.timezone(tz_name)
88
+ today = datetime.now(tz).date()
89
 
90
+ data = yf.download(tickers=symbol, interval="1m", period=training_period, progress=False)
91
  if data.empty:
92
+ return {"error": "No data from Yahoo Finance"}
93
 
94
+ data = data.tz_convert(tz_name)
95
  data['Date'] = data.index.date
 
 
 
 
 
 
96
  data_today = data[data['Date'] == today].between_time("09:15", "15:30")
97
  data_train = data[data['Date'] < today]
98
 
99
  if data_train.empty or data_today.empty:
100
+ return {"error": "Not enough data for training"}
101
 
102
+ full_data = pd.concat([data_train[['Close']], data_today[['Close']]])
103
  scaler = MinMaxScaler()
104
+ scaled_data = scaler.fit_transform(full_data)
105
 
106
+ X, y = create_dataset(scaled_data, time_step, p_step)
107
  X = X.reshape(X.shape[0], X.shape[1], 1)
108
 
 
109
  model = Sequential()
110
+ model.add(LSTM(50, return_sequences=False, input_shape=(time_step, 1)))
111
+ model.add(Dense(p_step))
112
  model.compile(loss='mean_squared_error', optimizer='adam')
113
+ model.fit(X, y, epochs=epochs, batch_size=batch_size, verbose=1)
114
 
115
+ # Save model and scaler
116
+ model_path = f"{MODEL_DIR}/{symbol}.h5"
117
+ scaler_path = f"{MODEL_DIR}/{symbol}_scaler.pkl"
118
+ model.save(model_path)
119
+ joblib.dump(scaler, scaler_path)
120
 
121
+ return {"status": f"Model trained and saved for {symbol}"}
122
 
123
+ # Prediction endpoint
124
  @app.get("/predict/{symbol}")
125
+ def predict(symbol: str, time_step: int = 60, p_step: int = 5):
126
+ model_path = f"{MODEL_DIR}/{symbol}.h5"
127
+ scaler_path = f"{MODEL_DIR}/{symbol}_scaler.pkl"
128
 
129
+ if not os.path.exists(model_path) or not os.path.exists(scaler_path):
130
+ return {"error": "Model not trained. Call /model/train first."}
131
 
132
+ stock_info = yf.Ticker(symbol).info
133
+ tz_name = stock_info.get('exchangeTimezoneName', 'UTC')
134
+ tz = pytz.timezone(tz_name)
135
+ now = datetime.now(tz)
136
+ today = now.date()
137
 
138
+ data = yf.download(tickers=symbol, interval="1m", period="1d", progress=False)
139
+ if data.empty:
140
+ return {"error": "No intraday data available"}
 
141
 
142
+ data = data.tz_convert(tz_name)
143
+ data['Date'] = data.index.date
144
+ data_today = data[data['Date'] == today].between_time("09:15", "15:30")
145
+
146
+ latest_data = data_today[['Close']].tail(time_step)
147
+ timestamps = data_today.index[-p_step:]
148
+
149
+ if len(latest_data) < time_step or len(timestamps) < p_step:
150
+ return {"error": "Not enough recent data for prediction"}
151
+
152
+ scaler = joblib.load(scaler_path)
153
+ model = load_model(model_path)
154
+
155
+ scaled_input = scaler.transform(latest_data)
156
+ input_data = scaled_input.reshape(1, time_step, 1)
157
+
158
+ predicted_scaled = model.predict(input_data)
159
  predicted_prices = scaler.inverse_transform(predicted_scaled.reshape(-1, 1)).flatten()
160
 
161
+ suggestion = profit_with_short_selling_json(predicted_prices, timestamps, symbol)
 
162
 
163
  return {
164
+ "symbol": symbol,
165
+ "timestamp": str(now),
166
+ "predicted_prices": predicted_prices.tolist(),
167
+ "suggestion": suggestion
168
  }