Spaces:
Running
Running
camphong24032002
commited on
Commit
·
048da70
1
Parent(s):
a754350
Update rsi and ichimoku api
Browse files- models/ichimoku.py +7 -3
- models/price.py +2 -2
- models/rsi.py +0 -1
- routes/data.py +7 -4
- services/indicator.py +68 -32
models/ichimoku.py
CHANGED
@@ -3,11 +3,15 @@ from pydantic import BaseModel, root_validator
|
|
3 |
|
4 |
class IchimokuPayload(BaseModel):
|
5 |
symbol: str
|
6 |
-
count_back: int =
|
7 |
-
|
|
|
|
|
|
|
|
|
8 |
|
9 |
@root_validator
|
10 |
def validate_dates(cls, values):
|
11 |
-
if values['
|
12 |
raise ValueError('type should be index or stock')
|
13 |
return values
|
|
|
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
|
models/price.py
CHANGED
@@ -4,10 +4,10 @@ from pydantic import BaseModel, root_validator
|
|
4 |
class PricePayload(BaseModel):
|
5 |
symbol: str
|
6 |
count_back: int = 365
|
7 |
-
|
8 |
|
9 |
@root_validator
|
10 |
def validate_dates(cls, values):
|
11 |
-
if values['
|
12 |
raise ValueError('type should be index or stock')
|
13 |
return values
|
|
|
4 |
class PricePayload(BaseModel):
|
5 |
symbol: str
|
6 |
count_back: int = 365
|
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
|
models/rsi.py
CHANGED
@@ -3,7 +3,6 @@ from pydantic import BaseModel
|
|
3 |
|
4 |
class RSIPayload(BaseModel):
|
5 |
symbol: str
|
6 |
-
range_selector: str = "1y"
|
7 |
periods: int = 14
|
8 |
smooth_k: int = 3
|
9 |
smooth_d: int = 3
|
|
|
3 |
|
4 |
class RSIPayload(BaseModel):
|
5 |
symbol: str
|
|
|
6 |
periods: int = 14
|
7 |
smooth_k: int = 3
|
8 |
smooth_d: int = 3
|
routes/data.py
CHANGED
@@ -17,7 +17,7 @@ router = APIRouter()
|
|
17 |
async def get_price_data(payload: PricePayload) -> Sequence[dict]:
|
18 |
price_df = Indicator.get_price(payload.symbol,
|
19 |
payload.count_back,
|
20 |
-
payload.
|
21 |
return json.loads(price_df.to_json(orient="records"))
|
22 |
|
23 |
|
@@ -29,7 +29,6 @@ async def get_price_data(payload: PricePayload) -> Sequence[dict]:
|
|
29 |
async def get_rsi_data(payload: RSIPayload) -> Sequence[dict]:
|
30 |
rsi_df = Indicator.get_rsi(
|
31 |
payload.symbol,
|
32 |
-
payload.range_selector,
|
33 |
payload.periods,
|
34 |
payload.smooth_k,
|
35 |
payload.smooth_d
|
@@ -45,6 +44,10 @@ async def get_rsi_data(payload: RSIPayload) -> Sequence[dict]:
|
|
45 |
async def get_ichimoku_data(payload: IchimokuPayload) -> Sequence[dict]:
|
46 |
price_df = Indicator.get_price(payload.symbol,
|
47 |
payload.count_back,
|
48 |
-
payload.
|
49 |
-
ichimoku_df = Indicator.get_ichimoku_cloud(price_df
|
|
|
|
|
|
|
|
|
50 |
return json.loads(ichimoku_df.to_json(orient="records"))
|
|
|
17 |
async def get_price_data(payload: PricePayload) -> Sequence[dict]:
|
18 |
price_df = Indicator.get_price(payload.symbol,
|
19 |
payload.count_back,
|
20 |
+
payload.symbol_type)
|
21 |
return json.loads(price_df.to_json(orient="records"))
|
22 |
|
23 |
|
|
|
29 |
async def get_rsi_data(payload: RSIPayload) -> Sequence[dict]:
|
30 |
rsi_df = Indicator.get_rsi(
|
31 |
payload.symbol,
|
|
|
32 |
payload.periods,
|
33 |
payload.smooth_k,
|
34 |
payload.smooth_d
|
|
|
44 |
async def get_ichimoku_data(payload: IchimokuPayload) -> Sequence[dict]:
|
45 |
price_df = Indicator.get_price(payload.symbol,
|
46 |
payload.count_back,
|
47 |
+
payload.symbol_type)
|
48 |
+
ichimoku_df = Indicator.get_ichimoku_cloud(price_df,
|
49 |
+
payload.conversion_period,
|
50 |
+
payload.base_period,
|
51 |
+
payload.span_b_period,
|
52 |
+
payload.displacement)
|
53 |
return json.loads(ichimoku_df.to_json(orient="records"))
|
services/indicator.py
CHANGED
@@ -1,10 +1,11 @@
|
|
1 |
import requests
|
2 |
-
import json
|
3 |
from datetime import datetime, timedelta
|
4 |
import pandas as pd
|
5 |
import numpy as np
|
6 |
-
from vnstock import longterm_ohlc_data
|
7 |
-
from
|
|
|
|
|
8 |
|
9 |
PREFIX = "https://www.hsx.vn/Modules/Chart/StaticChart/"
|
10 |
TIME = {"1m": 2, "3m": 3, "6m": 4, "1y": 5, "2y": 6, "5y": 7}
|
@@ -24,49 +25,84 @@ class Indicator:
|
|
24 |
|
25 |
@staticmethod
|
26 |
def get_price(symbol: str,
|
27 |
-
count_back: int =
|
28 |
-
|
29 |
resolution = "D"
|
30 |
end_date = datetime.now()
|
31 |
delta = timedelta(days=count_back)
|
32 |
start_date = end_date - delta
|
33 |
start_date = datetime.strftime(start_date, '%Y-%m-%d')
|
34 |
end_date = datetime.strftime(end_date, '%Y-%m-%d')
|
35 |
-
|
36 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
37 |
|
38 |
@staticmethod
|
39 |
def get_rsi(
|
40 |
symbol: str,
|
41 |
-
range_selector: str = "1y",
|
42 |
periods: int = 14,
|
43 |
smooth_k: int = 3,
|
44 |
smooth_d: int = 3,
|
45 |
) -> pd.DataFrame:
|
46 |
-
|
47 |
-
|
48 |
-
"
|
49 |
-
|
50 |
-
"
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
70 |
|
71 |
@staticmethod
|
72 |
def stoch_rsi(rsi: pd.Series, periods: int = 14) -> pd.Series:
|
|
|
1 |
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 |
+
import os
|
9 |
|
10 |
PREFIX = "https://www.hsx.vn/Modules/Chart/StaticChart/"
|
11 |
TIME = {"1m": 2, "3m": 3, "6m": 4, "1y": 5, "2y": 6, "5y": 7}
|
|
|
25 |
|
26 |
@staticmethod
|
27 |
def get_price(symbol: str,
|
28 |
+
count_back: int = 100,
|
29 |
+
symbol_type: str = "stock",) -> pd.DataFrame:
|
30 |
resolution = "D"
|
31 |
end_date = datetime.now()
|
32 |
delta = timedelta(days=count_back)
|
33 |
start_date = end_date - delta
|
34 |
start_date = datetime.strftime(start_date, '%Y-%m-%d')
|
35 |
end_date = datetime.strftime(end_date, '%Y-%m-%d')
|
36 |
+
df = longterm_ohlc_data(symbol, start_date, end_date,
|
37 |
+
resolution, symbol_type).reset_index(drop=True)
|
38 |
+
df[['open', 'high', 'low', 'close']] = \
|
39 |
+
df[['open', 'high', 'low', 'close']] * 1000
|
40 |
+
# convert open, high, low, close to int
|
41 |
+
df[['open', 'high', 'low', 'close']] = \
|
42 |
+
df[['open', 'high', 'low', 'close']].astype(int)
|
43 |
+
return df
|
44 |
|
45 |
@staticmethod
|
46 |
def get_rsi(
|
47 |
symbol: str,
|
|
|
48 |
periods: int = 14,
|
49 |
smooth_k: int = 3,
|
50 |
smooth_d: int = 3,
|
51 |
) -> pd.DataFrame:
|
52 |
+
try:
|
53 |
+
symbol = symbol.upper()
|
54 |
+
uri = os.environ.get("MONGODB_URI")
|
55 |
+
client = MongoClient(uri)
|
56 |
+
database = client.get_database("data")
|
57 |
+
collection = database.get_collection("rsi")
|
58 |
+
datetime_now = datetime.utcnow()
|
59 |
+
hour = datetime_now.hour
|
60 |
+
weekday = datetime_now.weekday()
|
61 |
+
error = False
|
62 |
+
if weekday < 5 and hour >= 12: # Check if data is updated
|
63 |
+
newest_record = collection.find_one(sort=[("_id", DESCENDING)])
|
64 |
+
delta = timedelta(days=20)
|
65 |
+
start_date = datetime_now - delta
|
66 |
+
start_date = start_date.strftime(DATE_FORMAT)
|
67 |
+
end_date = datetime_now.strftime(DATE_FORMAT)
|
68 |
+
tmp_df = stock_historical_data("MBB", start_date, end_date)
|
69 |
+
last_date = str(tmp_df["time"].iloc[-1])
|
70 |
+
if newest_record["time"] != last_date:
|
71 |
+
try:
|
72 |
+
lst_symbols = list(newest_record.keys())[2:]
|
73 |
+
record = {}
|
74 |
+
record["time"] = last_date
|
75 |
+
for s in lst_symbols:
|
76 |
+
url = PREFIX + INDICATORS["RSI"] + \
|
77 |
+
f"?stockSymbol={symbol}\
|
78 |
+
&rangeSelector=0\
|
79 |
+
&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(
|
84 |
+
sort=[("_id", ASCENDING)])
|
85 |
+
collection.insert_one(record)
|
86 |
+
print("Updated data")
|
87 |
+
except Exception:
|
88 |
+
error = True
|
89 |
+
records = list(collection.find())
|
90 |
+
record_df = pd.DataFrame(records).drop(columns=["_id"])
|
91 |
+
record_df = \
|
92 |
+
record_df[["time", symbol]].rename(columns={symbol: "rsi"})
|
93 |
+
if error:
|
94 |
+
new_df = price_board(symbol)
|
95 |
+
record_df.loc[len(record_df)] = new_df[["time", "RSI"]].values
|
96 |
+
record_df["stoch_rsi"] = \
|
97 |
+
Indicator.stoch_rsi(record_df["rsi"], periods)
|
98 |
+
record_df["stoch_rsi_smooth_k"] = \
|
99 |
+
Indicator.stoch_rsi_smooth_k(record_df["stoch_rsi"], smooth_k)
|
100 |
+
record_df["stoch_rsi_smooth_d"] = Indicator.stoch_rsi_smooth_d(
|
101 |
+
record_df["stoch_rsi_smooth_k"], smooth_d
|
102 |
+
)
|
103 |
+
return record_df
|
104 |
+
except Exception:
|
105 |
+
return None
|
106 |
|
107 |
@staticmethod
|
108 |
def stoch_rsi(rsi: pd.Series, periods: int = 14) -> pd.Series:
|