camphong24032002 commited on
Commit
e565da6
·
1 Parent(s): 90e3571

feat: update price and rsi data of vn100

Browse files
models/ichimoku.py CHANGED
@@ -1,17 +1,9 @@
1
- from pydantic import BaseModel, root_validator
2
 
3
 
4
  class IchimokuPayload(BaseModel):
5
  symbol: str
6
- count_back: int = 200
7
- symbol_type: str = "stock"
8
  conversion_period: int = 9
9
  base_period: int = 26
10
  span_b_period: int = 52
11
  displacement: int = 26
12
-
13
- @root_validator
14
- def validate_dates(cls, values):
15
- if values['symbol_type'] not in ["index", "stock"]:
16
- raise ValueError('type should be index or stock')
17
- return values
 
1
+ from pydantic import BaseModel
2
 
3
 
4
  class IchimokuPayload(BaseModel):
5
  symbol: str
 
 
6
  conversion_period: int = 9
7
  base_period: int = 26
8
  span_b_period: int = 52
9
  displacement: int = 26
 
 
 
 
 
 
models/price.py CHANGED
@@ -1,13 +1,5 @@
1
- from pydantic import BaseModel, root_validator
2
 
3
 
4
  class PricePayload(BaseModel):
5
  symbol: str
6
- count_back: int = 200
7
- symbol_type: str = "stock"
8
-
9
- @root_validator
10
- def validate_dates(cls, values):
11
- if values['symbol_type'] not in ["index", "stock"]:
12
- raise ValueError('type should be index or stock')
13
- return values
 
1
+ from pydantic import BaseModel
2
 
3
 
4
  class PricePayload(BaseModel):
5
  symbol: str
 
 
 
 
 
 
 
 
routes/data.py CHANGED
@@ -10,17 +10,39 @@ router = APIRouter()
10
 
11
 
12
  @router.get(
13
- "/update_rsi",
14
- name="Update RSI data",
15
  status_code=status.HTTP_200_OK
16
  )
17
- async def update_rsi_date():
18
- Indicator.get_rsi(
19
- symbol="FPT",
20
- periods=14,
21
- smooth_k=3,
22
- smooth_d=3
23
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
 
25
 
26
  @router.post(
@@ -29,9 +51,7 @@ async def update_rsi_date():
29
  status_code=status.HTTP_200_OK
30
  )
31
  async def get_price_data(payload: PricePayload) -> Sequence[dict]:
32
- price_df = Indicator.get_price(payload.symbol,
33
- payload.count_back,
34
- payload.symbol_type)
35
  if price_df is None:
36
  return [{"message": "Error"}]
37
  return json.loads(price_df.to_json(orient="records"))
@@ -60,9 +80,7 @@ async def get_rsi_data(payload: RSIPayload) -> Sequence[dict]:
60
  status_code=status.HTTP_200_OK
61
  )
62
  async def get_ichimoku_data(payload: IchimokuPayload) -> Sequence[dict]:
63
- price_df = Indicator.get_price(payload.symbol,
64
- payload.count_back,
65
- payload.symbol_type)
66
  ichimoku_df = Indicator.get_ichimoku_cloud(price_df,
67
  payload.conversion_period,
68
  payload.base_period,
 
10
 
11
 
12
  @router.get(
13
+ "/update_daily_price",
14
+ name="Update daily price data",
15
  status_code=status.HTTP_200_OK
16
  )
17
+ async def update_daily_price():
18
+ Indicator.update_daily_price()
19
+
20
+
21
+ @router.get(
22
+ "/update_entire_price",
23
+ name="Update entire price data",
24
+ status_code=status.HTTP_200_OK
25
+ )
26
+ async def update_entire_price():
27
+ Indicator.update_entire_price()
28
+
29
+
30
+ @router.get(
31
+ "/update_daily_rsi",
32
+ name="Update daily rsi data",
33
+ status_code=status.HTTP_200_OK
34
+ )
35
+ async def update_daily_rsi():
36
+ Indicator.update_daily_rsi()
37
+
38
+
39
+ @router.get(
40
+ "/update_entire_rsi",
41
+ name="Update entire rsi data",
42
+ status_code=status.HTTP_200_OK
43
+ )
44
+ async def update_entire_rsi():
45
+ Indicator.update_entire_rsi()
46
 
47
 
48
  @router.post(
 
51
  status_code=status.HTTP_200_OK
52
  )
53
  async def get_price_data(payload: PricePayload) -> Sequence[dict]:
54
+ price_df = Indicator.get_price(payload.symbol)
 
 
55
  if price_df is None:
56
  return [{"message": "Error"}]
57
  return json.loads(price_df.to_json(orient="records"))
 
80
  status_code=status.HTTP_200_OK
81
  )
82
  async def get_ichimoku_data(payload: IchimokuPayload) -> Sequence[dict]:
83
+ price_df = Indicator.get_price(payload.symbol)
 
 
84
  ichimoku_df = Indicator.get_ichimoku_cloud(price_df,
85
  payload.conversion_period,
86
  payload.base_period,
services/indicator.py CHANGED
@@ -2,9 +2,9 @@ import requests
2
  from datetime import datetime, timedelta
3
  import pandas as pd
4
  import numpy as np
5
- from vnstock import longterm_ohlc_data, stock_historical_data, price_board
6
  from pymongo import MongoClient, ASCENDING, DESCENDING
7
- from utils.config import DATE_FORMAT
8
  from .utils import Utility
9
  import os
10
  # from dotenv import load_dotenv
@@ -20,6 +20,9 @@ INDICATORS = {
20
  "Williams %R": "GetWilliamChart",
21
  "BollingerBand": "GetBollingerBandChart",
22
  }
 
 
 
23
 
24
 
25
  class Indicator:
@@ -27,23 +30,245 @@ class Indicator:
27
  pass
28
 
29
  @staticmethod
30
- def get_price(symbol: str,
31
- count_back: int = 200,
32
- symbol_type: str = "stock",) -> pd.DataFrame:
33
- resolution = "D"
34
- end_date = datetime.now()
35
- delta = timedelta(days=count_back)
36
- start_date = end_date - delta
37
- start_date = datetime.strftime(start_date, '%Y-%m-%d')
38
- end_date = datetime.strftime(end_date, '%Y-%m-%d')
39
- df = longterm_ohlc_data(symbol, start_date, end_date,
40
- resolution, symbol_type).reset_index(drop=True)
41
- df[['open', 'high', 'low', 'close']] = \
42
- df[['open', 'high', 'low', 'close']] * 1000
43
- # convert open, high, low, close to int
44
- df[['open', 'high', 'low', 'close']] = \
45
- df[['open', 'high', 'low', 'close']].astype(int)
46
- return df
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
 
48
  @staticmethod
49
  def get_rsi(
@@ -58,45 +283,13 @@ class Indicator:
58
  client = MongoClient(uri)
59
  database = client.get_database("data")
60
  collection = database.get_collection("rsi")
61
- datetime_now = datetime.utcnow()
62
- hour = datetime_now.hour
63
- weekday = datetime_now.weekday()
64
- error = False
65
- if weekday < 5 and hour >= 12: # Check if data is updated
66
- newest_record = collection.find_one(sort=[("_id", DESCENDING)])
67
- delta = timedelta(days=20)
68
- start_date = datetime_now - delta
69
- start_date = start_date.strftime(DATE_FORMAT)
70
- end_date = datetime_now.strftime(DATE_FORMAT)
71
- tmp_df = stock_historical_data(symbol, start_date, end_date)
72
- last_date = str(tmp_df["time"].iloc[-1])
73
- if newest_record["time"] != last_date:
74
- try:
75
- lst_symbols = list(newest_record.keys())[2:]
76
- record = {}
77
- record["time"] = last_date
78
- for s in lst_symbols:
79
- url = PREFIX + INDICATORS["RSI"] + f"?stockSymbol={s}&rangeSelector=2&periods={periods}"
80
- data = requests.get(url).json()
81
- lst_rsi = data["SeriesColection"][0]["Points"]
82
- record[s] = lst_rsi[-1]["Value"][0]
83
- collection.find_one_and_delete({}, sort=[("_id", ASCENDING)])
84
- collection.insert_one(record)
85
- print("Updated data")
86
- except Exception:
87
- error = True
88
  try:
89
  records = list(collection.find())
90
  except Exception as e:
91
  print(f"Error: {e}")
92
- print("load successfully")
93
  record_df = pd.DataFrame(records).drop(columns=["_id"])
94
  record_df = \
95
  record_df[["time", symbol]].rename(columns={symbol: "rsi"})
96
- if error:
97
- new_df = price_board(symbol)
98
- value = [last_date, new_df["RSI"][0]]
99
- record_df.loc[len(record_df)] = value
100
  record_df["stoch_rsi"] = \
101
  Indicator.stoch_rsi(record_df["rsi"], periods)
102
  record_df["stoch_rsi_smooth_k"] = \
 
2
  from datetime import datetime, timedelta
3
  import pandas as pd
4
  import numpy as np
5
+ from vnstock import longterm_ohlc_data
6
  from pymongo import MongoClient, ASCENDING, DESCENDING
7
+ from utils.config import DATE_FORMAT, VN100_URL
8
  from .utils import Utility
9
  import os
10
  # from dotenv import load_dotenv
 
20
  "Williams %R": "GetWilliamChart",
21
  "BollingerBand": "GetBollingerBandChart",
22
  }
23
+ updating_price = False
24
+ updating_rsi = False
25
+ updating_macd = False
26
 
27
 
28
  class Indicator:
 
30
  pass
31
 
32
  @staticmethod
33
+ def update_daily_price() -> None:
34
+ global updating_price
35
+ if updating_price:
36
+ return
37
+ updating_price = True
38
+ datetime_now = datetime.utcnow()
39
+ hour = datetime_now.hour
40
+ weekday = datetime_now.weekday()
41
+ start_date = datetime_now.date()
42
+ delta = timedelta(days=1)
43
+ end_date = start_date + delta
44
+ start_date = start_date.strftime(DATE_FORMAT)
45
+ end_date = end_date.strftime(DATE_FORMAT)
46
+ try:
47
+ if weekday < 5 and hour >= 12:
48
+ uri = os.environ.get("MONGODB_URI")
49
+ client = MongoClient(uri)
50
+ database = client.get_database("data")
51
+ collection = database.get_collection("price")
52
+ tmp_df = longterm_ohlc_data("MBB",
53
+ start_date,
54
+ end_date,
55
+ "D",
56
+ "stock").reset_index(drop=True)
57
+ if tmp_df.shape[0] == 0:
58
+ updating_price = False
59
+ return
60
+ last_date = str(tmp_df["time"])
61
+ newest_record = \
62
+ collection.find_one(sort=[("_id", DESCENDING)])
63
+ if newest_record["time"] != last_date:
64
+ lst_symbols = list(newest_record["value"].keys())
65
+ record = {}
66
+ record["time"] = last_date
67
+ values = []
68
+ for symbol in lst_symbols:
69
+ df = longterm_ohlc_data(symbol,
70
+ start_date,
71
+ end_date,
72
+ resolution="D",
73
+ type="stock"
74
+ ).reset_index(drop=True)
75
+ df[["open", "high", "low", "close"]] = \
76
+ df[["open", "high", "low", "close"]] * 1000
77
+ # convert open, high, low, close to int
78
+ df[["open", "high", "low", "close"]] = \
79
+ df[["open", "high", "low", "close"]].astype(int)
80
+ df = df[["ticker", "open",
81
+ "high", "low", "close"]].iloc[-1]
82
+ values.append(df.to_dict())
83
+ record["value"] = values
84
+ collection.insert_one(record)
85
+ collection.find_one_and_delete({}, sort=[("_id", ASCENDING)])
86
+ print("Updated price")
87
+ updating_price = False
88
+ except Exception as e:
89
+ print(f"Error: {e}")
90
+ updating_price = False
91
+
92
+ @staticmethod
93
+ def update_entire_price() -> None:
94
+ global updating_price
95
+ if updating_price:
96
+ return
97
+ updating_price = True
98
+ datetime_now = datetime.utcnow()
99
+ hour = datetime_now.hour
100
+ weekday = datetime_now.weekday()
101
+ try:
102
+ data = requests.get(VN100_URL).json()
103
+ data = data["rows"]
104
+ lst_symbols = []
105
+ for value in data:
106
+ lst_symbols.append(value["cell"][2].strip())
107
+ if weekday < 5 and hour < 12:
108
+ return
109
+ end_date = datetime_now.date()
110
+ delta = timedelta(days=300)
111
+ start_date = end_date - delta
112
+ start_date = start_date.strftime(DATE_FORMAT)
113
+ end_date = end_date.strftime(DATE_FORMAT)
114
+ lst_time = []
115
+ lst_values = []
116
+ if len(lst_symbols) != 100:
117
+ return
118
+ for symbol in lst_symbols:
119
+ df = longterm_ohlc_data(symbol,
120
+ start_date,
121
+ end_date,
122
+ resolution="D",
123
+ type="stock"
124
+ ).reset_index(drop=True).tail(150)
125
+ lst_time = list(df["time"])
126
+ df[["open", "high", "low", "close"]] = \
127
+ df[["open", "high", "low", "close"]] * 1000
128
+ # convert open, high, low, close to int
129
+ df[["open", "high", "low", "close"]] = \
130
+ df[["open", "high", "low", "close"]].astype(int)
131
+ df = df[["ticker", "open", "high", "low", "close"]]
132
+ lst_values.append(df.to_dict(orient="records"))
133
+ records = []
134
+ for i in range(len(lst_time)):
135
+ record = {}
136
+ record["time"] = lst_time[i]
137
+ values = []
138
+ for symbol_index in range(100):
139
+ values.append(lst_values[symbol_index][i])
140
+ record["value"] = values
141
+ records.append(record)
142
+ uri = os.environ.get("MONGODB_URI")
143
+ client = MongoClient(uri)
144
+ database = client.get_database("data")
145
+ collection = database.get_collection("price")
146
+ if "price" in database.list_collection_names():
147
+ collection.drop()
148
+ collection.insert_many(records)
149
+ print("Updated entire price")
150
+ updating_price = False
151
+ except Exception as e:
152
+ print(f"Error: {e}")
153
+ updating_price = False
154
+
155
+ @staticmethod
156
+ def get_price(symbol) -> pd.DataFrame:
157
+ try:
158
+ symbol = symbol.upper()
159
+ uri = os.environ.get("MONGODB_URI")
160
+ client = MongoClient(uri)
161
+ database = client.get_database("data")
162
+ collection = database.get_collection("price")
163
+ result = list(collection.find())
164
+ tmp_df = pd.DataFrame(result[0]["value"])
165
+ lst_symbols = tmp_df["ticker"].values
166
+ if symbol not in lst_symbols:
167
+ return None
168
+ symbol_index = np.argwhere(lst_symbols == symbol)[0][0]
169
+ lst_values = []
170
+ for record in result:
171
+ value = record["value"][symbol_index]
172
+ value["time"] = record["time"]
173
+ lst_values.append(value)
174
+ return pd.DataFrame(lst_values)
175
+ except Exception:
176
+ return None
177
+
178
+ @staticmethod
179
+ def update_daily_rsi() -> None:
180
+ global updating_rsi
181
+ if updating_rsi:
182
+ return
183
+ updating_rsi = True
184
+ datetime_now = datetime.utcnow()
185
+ hour = datetime_now.hour
186
+ weekday = datetime_now.weekday()
187
+ start_date = datetime_now.date()
188
+ delta = timedelta(days=1)
189
+ end_date = start_date + delta
190
+ start_date = start_date.strftime(DATE_FORMAT)
191
+ end_date = end_date.strftime(DATE_FORMAT)
192
+ try:
193
+ if weekday < 5 and hour >= 12:
194
+ uri = os.environ.get("MONGODB_URI")
195
+ client = MongoClient(uri)
196
+ database = client.get_database("data")
197
+ collection = database.get_collection("price")
198
+ tmp_df = longterm_ohlc_data("MBB",
199
+ start_date,
200
+ end_date,
201
+ "D",
202
+ "stock").reset_index(drop=True)
203
+ if tmp_df.shape[0] == 0:
204
+ return
205
+ last_date = str(tmp_df["time"])
206
+ newest_record = \
207
+ collection.find_one(sort=[("_id", DESCENDING)])
208
+ if newest_record["time"] != last_date:
209
+ lst_symbols = list(newest_record["value"].keys())
210
+ record = {}
211
+ record["time"] = last_date
212
+ str_symbols = ','.join(lst_symbols)
213
+ data = requests.get('https://apipubaws.tcbs.com.vn/stock-insight/v1/stock/second-tc-price?tickers={}'.format(str_symbols)).json()
214
+ for i in data["data"]:
215
+ record[i["t"]] = i["rsi"]
216
+ collection.insert_one(record)
217
+ collection.find_one_and_delete({}, sort=[("_id", ASCENDING)])
218
+ print("Updated daily rsi")
219
+ updating_rsi = False
220
+ except Exception as e:
221
+ print(f"Error: {e}")
222
+ updating_rsi = False
223
+
224
+ @staticmethod
225
+ def update_entire_rsi() -> None:
226
+ global updating_rsi
227
+ if updating_rsi:
228
+ return
229
+ updating_rsi = True
230
+ datetime_now = datetime.utcnow()
231
+ hour = datetime_now.hour
232
+ weekday = datetime_now.weekday()
233
+ try:
234
+ data = requests.get(VN100_URL).json()
235
+ data = data["rows"]
236
+ lst_symbols = []
237
+ for value in data:
238
+ lst_symbols.append(value["cell"][2].strip())
239
+ if weekday < 5 and hour < 12:
240
+ return
241
+ get_time = True
242
+ lst_values = {}
243
+ if len(lst_symbols) != 100:
244
+ return
245
+ cnt = 0
246
+ for symbol in lst_symbols:
247
+ cnt += 1
248
+ url = PREFIX + INDICATORS["RSI"] \
249
+ + f"?stockSymbol={symbol}&rangeSelector=3&periods=14"
250
+ data = requests.get(url).json()
251
+ rsi_df = pd.DataFrame(data["SeriesColection"][0]["Points"])
252
+ if get_time:
253
+ lst_values["time"] = \
254
+ rsi_df["Time"].apply(lambda x:
255
+ Utility.ts_to_date(x/1000))
256
+ get_time = False
257
+ lst_values[symbol] = rsi_df["Value"].apply(lambda x: x[0])
258
+ df = pd.DataFrame(lst_values)
259
+ records = df.to_dict(orient="records")
260
+ uri = os.environ.get("MONGODB_URI")
261
+ client = MongoClient(uri)
262
+ database = client.get_database("data")
263
+ collection = database.get_collection("rsi")
264
+ if "rsi" in database.list_collection_names():
265
+ collection.drop()
266
+ collection.insert_many(records)
267
+ print("Updated entire RSI")
268
+ updating_rsi = False
269
+ except Exception as e:
270
+ print(f"Error: {e}")
271
+ updating_rsi = False
272
 
273
  @staticmethod
274
  def get_rsi(
 
283
  client = MongoClient(uri)
284
  database = client.get_database("data")
285
  collection = database.get_collection("rsi")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
286
  try:
287
  records = list(collection.find())
288
  except Exception as e:
289
  print(f"Error: {e}")
 
290
  record_df = pd.DataFrame(records).drop(columns=["_id"])
291
  record_df = \
292
  record_df[["time", symbol]].rename(columns={symbol: "rsi"})
 
 
 
 
293
  record_df["stoch_rsi"] = \
294
  Indicator.stoch_rsi(record_df["rsi"], periods)
295
  record_df["stoch_rsi_smooth_k"] = \
utils/backup.py DELETED
@@ -1,11 +0,0 @@
1
- from pymongo.mongo_client import MongoClient
2
- from pymongo.server_api import ServerApi
3
- uri = "mongodb+srv://dacap3h:vMRoeFxX7Jjn2O5m@backup-data.m6pxu2j.mongodb.net/"
4
- # Create a new client and connect to the server
5
- client = MongoClient(uri, server_api=ServerApi('1'))
6
- # Send a ping to confirm a successful connection
7
- try:
8
- client.admin.command('ping')
9
- print("Pinged your deployment. You successfully connected to MongoDB!")
10
- except Exception as e:
11
- print(e)
 
 
 
 
 
 
 
 
 
 
 
 
utils/config.py CHANGED
@@ -10,3 +10,4 @@ tcbs_headers = {
10
  'Referer': 'https://tcinvest.tcbs.com.vn/',
11
  'sec-ch-ua-platform': '"Windows"'
12
  }
 
 
10
  'Referer': 'https://tcinvest.tcbs.com.vn/',
11
  'sec-ch-ua-platform': '"Windows"'
12
  }
13
+ VN100_URL = "https://www.hsx.vn/Modules/Listed/Web/StockIndex/188803177?_search=false&nd=1707328622054&rows=2147483647&page=1&sidx=id&sord=desc"