camphong24032002 commited on
Commit
884dad1
·
1 Parent(s): 665d6af

Initialize

Browse files
.gitattributes copy ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,160 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py,cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # poetry
98
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102
+ #poetry.lock
103
+
104
+ # pdm
105
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106
+ #pdm.lock
107
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108
+ # in version control.
109
+ # https://pdm.fming.dev/#use-with-ide
110
+ .pdm.toml
111
+
112
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
113
+ __pypackages__/
114
+
115
+ # Celery stuff
116
+ celerybeat-schedule
117
+ celerybeat.pid
118
+
119
+ # SageMath parsed files
120
+ *.sage.py
121
+
122
+ # Environments
123
+ .env
124
+ .venv
125
+ env/
126
+ venv/
127
+ ENV/
128
+ env.bak/
129
+ venv.bak/
130
+
131
+ # Spyder project settings
132
+ .spyderproject
133
+ .spyproject
134
+
135
+ # Rope project settings
136
+ .ropeproject
137
+
138
+ # mkdocs documentation
139
+ /site
140
+
141
+ # mypy
142
+ .mypy_cache/
143
+ .dmypy.json
144
+ dmypy.json
145
+
146
+ # Pyre type checker
147
+ .pyre/
148
+
149
+ # pytype static type analyzer
150
+ .pytype/
151
+
152
+ # Cython debug symbols
153
+ cython_debug/
154
+
155
+ # PyCharm
156
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
157
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
158
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
159
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
160
+ #.idea/
Dockerfile ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.9
2
+
3
+ RUN apt-get update && apt-get install -y \
4
+ libgl1-mesa-glx \
5
+ && rm -rf /var/lib/apt/lists/*
6
+
7
+ WORKDIR /code
8
+
9
+ COPY ./requirements.txt /code/requirements.txt
10
+
11
+ RUN pip install --upgrade pip
12
+
13
+ RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
14
+
15
+ COPY . .
16
+
17
+ RUN chown -R 1000:1000 /code
18
+
19
+ USER 1000
20
+
21
+ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
README copy.md ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Data Api
3
+ emoji: ⚡
4
+ colorFrom: red
5
+ colorTo: blue
6
+ sdk: docker
7
+ pinned: false
8
+ ---
9
+
10
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
main.py ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI
2
+ from starlette.middleware.cors import CORSMiddleware
3
+ from routes.data import router as DataRouter
4
+
5
+ app = FastAPI(title="Stock data API", docs_url="/docs", version="0.1.0")
6
+
7
+
8
+ app.include_router(DataRouter, tags=["Data"], prefix="/data")
9
+
10
+
11
+ @app.get("/", tags=["Root"])
12
+ async def read_root():
13
+ return {"message": "Stock Data API v1"}
14
+
15
+
16
+ app.add_middleware(
17
+ CORSMiddleware,
18
+ allow_origins=["*"],
19
+ allow_credentials=True,
20
+ allow_methods=["POST", "PUT", "DELETE", "OPTION", "GET"],
21
+ allow_headers=["*"],
22
+ )
models/__init__.py ADDED
File without changes
models/ichimoku.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel, root_validator
2
+
3
+
4
+ class IchimokuPayload(BaseModel):
5
+ symbol: str
6
+ count_back: int = 365
7
+ type: str = "stock"
8
+
9
+ @root_validator
10
+ def validate_dates(cls, values):
11
+ if values['type'] not in ["index", "stock"]:
12
+ raise ValueError('type should be index or stock')
13
+ return values
models/price.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel, root_validator
2
+
3
+
4
+ class PricePayload(BaseModel):
5
+ symbol: str
6
+ count_back: int = 365
7
+ type: str = "stock"
8
+
9
+ @root_validator
10
+ def validate_dates(cls, values):
11
+ if values['type'] not in ["index", "stock"]:
12
+ raise ValueError('type should be index or stock')
13
+ return values
models/rsi.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel
2
+
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
requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ fastapi
2
+ uvicorn
3
+ pydantic
4
+ requests
5
+ pandas
6
+ numpy
7
+ pymongo
8
+ vnstock
routes/__init__.py ADDED
File without changes
routes/data.py ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from services.indicator import Indicator
2
+ from models.ichimoku import IchimokuPayload
3
+ from models.rsi import RSIPayload
4
+ from models.price import PricePayload
5
+ from fastapi import status, APIRouter
6
+ from typing import Sequence
7
+ import json
8
+
9
+ router = APIRouter()
10
+
11
+
12
+ @router.post(
13
+ "/get_price",
14
+ name="Get price",
15
+ status_code=status.HTTP_200_OK
16
+ )
17
+ async def get_price_data(payload: PricePayload) -> Sequence[dict]:
18
+ price_df = Indicator.get_price(payload.symbol,
19
+ payload.count_back,
20
+ payload.type)
21
+ return json.loads(price_df.to_json(orient="records"))
22
+
23
+
24
+ @router.post(
25
+ "/get_rsi",
26
+ name="Get data of RSI",
27
+ status_code=status.HTTP_200_OK
28
+ )
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
36
+ )
37
+ return json.loads(rsi_df.to_json(orient="records"))
38
+
39
+
40
+ @router.post(
41
+ "/get_ichimoku",
42
+ name="Get data of Ichimoku cloud",
43
+ status_code=status.HTTP_200_OK
44
+ )
45
+ async def get_ichimoku_data(payload: IchimokuPayload) -> Sequence[dict]:
46
+ price_df = Indicator.get_price(payload.symbol,
47
+ payload.count_back,
48
+ payload.type)
49
+ ichimoku_df = Indicator.get_ichimoku_cloud(price_df)
50
+ return json.loads(ichimoku_df.to_json(orient="records"))
services/__init__.py ADDED
File without changes
services/indicator.py ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 .utils import Utility
8
+
9
+ PREFIX = "https://www.hsx.vn/Modules/Chart/StaticChart/"
10
+ TIME = {"1m": 2, "3m": 3, "6m": 4, "1y": 5, "2y": 6, "5y": 7}
11
+ INDICATORS = {
12
+ "EMA": "GetEmaChart",
13
+ "MACD": "GetMacdChart",
14
+ "RSI": "GetRsiChart",
15
+ "Momentum": "GetMomentumChart",
16
+ "Williams %R": "GetWilliamChart",
17
+ "BollingerBand": "GetBollingerBandChart",
18
+ }
19
+
20
+
21
+ class Indicator:
22
+ def __init__(self) -> None:
23
+ pass
24
+
25
+ @staticmethod
26
+ def get_price(symbol: str,
27
+ count_back: int = 365,
28
+ type: str = "stock",) -> pd.DataFrame:
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
+ return longterm_ohlc_data(symbol, start_date, end_date,
36
+ resolution, type).reset_index()
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
+ range_selector = TIME[range_selector]
47
+ params = {
48
+ "stockSymbol": symbol,
49
+ "rangeSelector": range_selector,
50
+ "period": periods,
51
+ }
52
+ lst_param = []
53
+ for key, value in params.items():
54
+ lst_param.append(f"{key}={value}")
55
+ url = PREFIX + INDICATORS["RSI"] + "?" + "&".join(lst_param)
56
+ response = requests.get(url)
57
+ data = json.loads(response.text)
58
+ rsi_df = pd.DataFrame(data["SeriesColection"][0]["Points"])
59
+ rsi_df["time"] = \
60
+ rsi_df["Time"].apply(lambda x: Utility.ts_to_date(x/1000))
61
+ rsi_df["rsi"] = rsi_df["Value"].apply(lambda x: x[0])
62
+ rsi_df = rsi_df[["date", "rsi"]]
63
+ rsi_df["stoch_rsi"] = Indicator.stoch_rsi(rsi_df["rsi"], periods)
64
+ rsi_df["stoch_rsi_smooth_k"] = \
65
+ Indicator.stoch_rsi_smooth_k(rsi_df["stoch_rsi"], smooth_k)
66
+ rsi_df["stoch_rsi_smooth_d"] = Indicator.stoch_rsi_smooth_d(
67
+ rsi_df["stoch_rsi_smooth_k"], smooth_d
68
+ )
69
+ return rsi_df
70
+
71
+ @staticmethod
72
+ def stoch_rsi(rsi: pd.Series, periods: int = 14) -> pd.Series:
73
+ ma, mi = (
74
+ rsi.rolling(window=periods).max(),
75
+ rsi.rolling(window=periods).min(),
76
+ )
77
+ return (rsi - mi) * 100 / (ma - mi)
78
+
79
+ @staticmethod
80
+ def stoch_rsi_smooth_k(stoch_rsi: pd.Series, k: int) -> pd.Series:
81
+ return stoch_rsi.rolling(window=k).mean()
82
+
83
+ @staticmethod
84
+ def stoch_rsi_smooth_d(stoch_rsi_k: pd.Series, d: int) -> pd.Series:
85
+ return stoch_rsi_k.rolling(window=d).mean()
86
+
87
+ @staticmethod
88
+ def get_ichimoku_cloud(
89
+ df: pd.DataFrame,
90
+ conversion_period=9,
91
+ base_period=26,
92
+ span_b_period=52,
93
+ displacement=26,
94
+ ) -> pd.DataFrame:
95
+ space_displacement = np.full(displacement, np.nan)
96
+ tenkan_sen = (
97
+ df["high"].rolling(window=conversion_period).max()
98
+ + df["low"].rolling(window=conversion_period).min()
99
+ ) / 2
100
+ kijun_sen = (
101
+ df["high"].rolling(window=base_period).max()
102
+ + df["low"].rolling(window=base_period).min()
103
+ ) / 2
104
+ senkou_span_a = (tenkan_sen + kijun_sen) / 2
105
+ senkou_span_b = (
106
+ df["high"].rolling(window=span_b_period).max()
107
+ + df["low"].rolling(window=span_b_period).min()
108
+ ) / 2
109
+ chikou_span = df["close"].shift(-displacement)
110
+
111
+ date_displacement = np.array(
112
+ list(map(str, np.arange(1, displacement+1))))
113
+ time = np.concatenate((df["time"], date_displacement))
114
+ tenkan_sen = np.concatenate((tenkan_sen, space_displacement))
115
+ kijun_sen = np.concatenate((kijun_sen, space_displacement))
116
+ senkou_span_a = np.concatenate((space_displacement, senkou_span_a))
117
+ senkou_span_b = np.concatenate((space_displacement, senkou_span_b))
118
+ chikou_span = np.concatenate((chikou_span, space_displacement))
119
+
120
+ data_dict = {
121
+ "time": time,
122
+ "tenkan_sen": tenkan_sen,
123
+ "kijun_sen": kijun_sen,
124
+ "senkou_span_a": senkou_span_a,
125
+ "senkou_span_b": senkou_span_b,
126
+ "chikou_span": chikou_span,
127
+ "tenkan_kijun": tenkan_sen - kijun_sen,
128
+ "kumo_cloud": senkou_span_a - senkou_span_b,
129
+ "signal": senkou_span_a > senkou_span_b,
130
+ }
131
+ return pd.DataFrame(data_dict)
services/utils.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from datetime import datetime
2
+ from utils.config import DATE_FORMAT
3
+
4
+
5
+ class Utility:
6
+ def __init__(self) -> None: pass
7
+
8
+ @staticmethod
9
+ def ts_to_date(ts, format=DATE_FORMAT) -> str:
10
+ return datetime.fromtimestamp(ts).strftime(format)
11
+
12
+ @staticmethod
13
+ def date_to_ts(date, format=DATE_FORMAT) -> int:
14
+ return int(datetime.timestamp(datetime.strptime(date, format)))
utils/__init__.py ADDED
File without changes
utils/backup.py ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
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 ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ DATE_FORMAT = "%Y-%m-%d"
2
+ tcbs_headers = {
3
+ 'sec-ch-ua': '"Google Chrome";v="119", "Chromium";v="119", "Not?A_Brand";v="24"',
4
+ 'DNT': '1',
5
+ 'Accept-language': 'vi',
6
+ 'sec-ch-ua-mobile': '?0',
7
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36',
8
+ 'Content-Type': 'application/json',
9
+ 'Accept': 'application/json',
10
+ 'Referer': 'https://tcinvest.tcbs.com.vn/',
11
+ 'sec-ch-ua-platform': '"Windows"'
12
+ }