CoolFace
Apppublic

IntelliStock/data-api

sourceHugging Faceupdated 3y agoView on Hugging Face
0likes
indicator.py501 linesDownload Raw Back to services
1import requests2from datetime import datetime, timedelta3import pandas as pd4import numpy as np5from vnstock import longterm_ohlc_data6from pymongo import MongoClient, ASCENDING, DESCENDING7from utils.config import DATE_FORMAT, VN100_URL8from .utils import Utility9import os10# from dotenv import load_dotenv11# load_dotenv()12 13PREFIX = "https://www.hsx.vn/Modules/Chart/StaticChart/"14TIME = {"1m": 2, "3m": 3, "6m": 4, "1y": 5, "2y": 6, "5y": 7}15INDICATORS = {16    "EMA": "GetEmaChart",17    "MACD": "GetMacdChart",18    "RSI": "GetRsiChart",19    "Momentum": "GetMomentumChart",20    "Williams %R": "GetWilliamChart",21    "BollingerBand": "GetBollingerBandChart",22}23updating_price = False24updating_rsi = False25updating_macd = False26 27 28class Indicator:29    def __init__(self) -> None:30        pass31 32    @staticmethod33    def get_vn100(source: str = "database") -> dict:34        try:35            lst_symbols = []36            if source == "database":37                uri = os.environ.get("MONGODB_URI")38                client = MongoClient(uri)39                database = client.get_database("data")40                collection = database.get_collection("rsi")41                newest_record = collection.find_one(sort=[("_id", ASCENDING)])42                lst_symbols = list(newest_record.keys())[2:]43            elif source == "hsx":44                data = requests.get(VN100_URL).json()45                data = data["rows"]46                for value in data:47                    lst_symbols.append(value["cell"][2].strip())48            return {"symbols": lst_symbols}49        except Exception as e:50            return {"message": f"Caught error {e}."}51 52    @staticmethod53    async def update_daily_price() -> dict:54        global updating_price55        if updating_price:56            print("The data has been updating.")57            return58        updating_price = True59        datetime_now = datetime.utcnow()60        hour = datetime_now.hour61        weekday = datetime_now.weekday()62        end_date = datetime_now.date()63        delta = timedelta(days=5)64        start_date = end_date - delta65        start_date = start_date.strftime(DATE_FORMAT)66        end_date = end_date.strftime(DATE_FORMAT)67        try:68            if weekday < 5 and hour >= 12:69                uri = os.environ.get("MONGODB_URI")70                client = MongoClient(uri)71                database = client.get_database("data")72                collection = database.get_collection("price")73                tmp_df = longterm_ohlc_data("FPT",74                                            start_date,75                                            end_date,76                                            "D",77                                            "stock").reset_index(drop=True)78                if tmp_df.shape[0] == 0:79                    updating_price = False80                    print("There is no data to updated")81                    return82                tmp_df = tmp_df.iloc[-1]83                last_date = str(tmp_df["time"])84                newest_record = \85                    collection.find_one(sort=[("_id", DESCENDING)])86                ret = None87                if newest_record["time"] != last_date:88                    rsi_collection = database.get_collection("rsi")89                    tmp_record = \90                        rsi_collection.find_one(sort=[("_id", DESCENDING)])91                    lst_symbols = list(tmp_record.keys())[2:]92                    record = {}93                    record["time"] = last_date94                    values = []95                    for symbol in lst_symbols:96                        df = longterm_ohlc_data(symbol,97                                                start_date,98                                                end_date,99                                                resolution="D",100                                                type="stock"101                                                ).reset_index(drop=True)102                        df[["open", "high", "low", "close"]] = \103                            df[["open", "high", "low", "close"]] * 1000104                        # convert open, high, low, close to int105                        df[["open", "high", "low", "close"]] = \106                            df[["open", "high", "low", "close"]].astype(int)107                        df = df[["ticker", "open",108                                "high", "low", "close", "volume"]].iloc[-1]109                        values.append(df.to_dict())110                    record["value"] = values111                    collection.insert_one(record)112                    ret = "Updated data."113                else:114                    ret = "The data is up to date."115                updating_price = False116                print(ret)117        except Exception as e:118            updating_price = False119            print(f"Caught error {e}.")120 121    @staticmethod122    def update_entire_price() -> None:123        global updating_price124        if updating_price:125            return {"message": "The data has been updating."}126        updating_price = True127        datetime_now = datetime.utcnow()128        hour = datetime_now.hour129        weekday = datetime_now.weekday()130        try:131            symbol_dict = Indicator.get_vn100(source="hsx")132            lst_symbols = symbol_dict["symbols"]133            if weekday < 5 and hour < 12:134                updating_price = False135                return {"message": "The market is in trading."}136            end_date = datetime_now.date()137            delta = timedelta(days=350)138            start_date = end_date - delta139            start_date = start_date.strftime(DATE_FORMAT)140            end_date = end_date.strftime(DATE_FORMAT)141            lst_time = []142            lst_values = []143            if len(lst_symbols) != 100:144                updating_price = False145                return {"message": "Not enough 100 symbols."}146            for symbol in lst_symbols:147                df = longterm_ohlc_data(symbol,148                                        start_date,149                                        end_date,150                                        resolution="D",151                                        type="stock"152                                        ).reset_index(drop=True).tail(205)153                lst_time = list(df["time"])154                df[["open", "high", "low", "close"]] = \155                    df[["open", "high", "low", "close"]] * 1000156                # convert open, high, low, close to int157                df[["open", "high", "low", "close"]] = \158                    df[["open", "high", "low", "close"]].astype(int)159                df = df[["ticker", "open", "high", "low", "close", "volume"]]160                lst_values.append(df.to_dict(orient="records"))161            records = []162            for i in range(len(lst_time)):163                record = {}164                record["time"] = lst_time[i]165                values = []166                for symbol_index in range(100):167                    values.append(lst_values[symbol_index][i])168                record["value"] = values169                records.append(record)170            uri = os.environ.get("MONGODB_URI")171            client = MongoClient(uri)172            database = client.get_database("data")173            collection = database.get_collection("price")174            if "price" in database.list_collection_names():175                collection.drop()176            collection.insert_many(records)177            updating_price = False178            return {"message": "Updated data."}179        except Exception as e:180            updating_price = False181            return {"message": f"Caught error {e}."}182 183    @staticmethod184    def get_price(symbol: str,185                  count_back: int = 150,186                  source: str = "database") -> pd.DataFrame:187        try:188            symbol = symbol.upper()189            if source == "database":190                uri = os.environ.get("MONGODB_URI")191                client = MongoClient(uri)192                database = client.get_database("data")193                collection = database.get_collection("price")194                result = list(collection.find())195                tmp_df = pd.DataFrame(result[0]["value"])196                lst_symbols = tmp_df["ticker"].values197                if symbol not in lst_symbols:198                    return pd.DataFrame(199                        [{"message": "The symbol is not existed"}]200                        )201                symbol_index = np.argwhere(lst_symbols == symbol)[0][0]202                lst_values = []203                for record in result:204                    value = record["value"][symbol_index]205                    value["time"] = record["time"]206                    lst_values.append(value)207                return pd.DataFrame(lst_values)208            elif source == "vnstock":209                datetime_now = datetime.utcnow()210                end_date = datetime_now.date()211                delta = timedelta(days=count_back)212                start_date = end_date - delta213                start_date = start_date.strftime(DATE_FORMAT)214                end_date = end_date.strftime(DATE_FORMAT)215                df = longterm_ohlc_data(symbol,216                                        start_date,217                                        end_date,218                                        resolution="D",219                                        type="stock"220                                        ).reset_index(drop=True)221                df[["open", "high", "low", "close"]] = \222                    df[["open", "high", "low", "close"]] * 1000223                # convert open, high, low, close to int224                df[["open", "high", "low", "close"]] = \225                    df[["open", "high", "low", "close"]].astype(int)226                return df[["time", "ticker", "open", "high", "low", "close"]]227        except Exception as e:228            return pd.DataFrame(229                [{"message": f"Caught error {e}."}]230                )231 232    @staticmethod233    async def update_daily_rsi() -> None:234        global updating_rsi235        if updating_rsi:236            print("The data has been updating.")237            return238            # return {"message": "The data has been updating."}239        updating_rsi = True240        datetime_now = datetime.utcnow()241        hour = datetime_now.hour242        weekday = datetime_now.weekday()243        end_date = datetime_now.date()244        delta = timedelta(days=5)245        start_date = end_date - delta246        start_date = start_date.strftime(DATE_FORMAT)247        end_date = end_date.strftime(DATE_FORMAT)248        try:249            ret = None250            if weekday < 5 and hour >= 12:251                uri = os.environ.get("MONGODB_URI")252                client = MongoClient(uri)253                database = client.get_database("data")254                collection = database.get_collection("rsi")255                tmp_df = longterm_ohlc_data("FPT",256                                            start_date,257                                            end_date,258                                            "D",259                                            "stock").reset_index(drop=True)260                if tmp_df.shape[0] == 0:261                    updating_rsi = False262                    print("The market is in trading.")263                    return264                    # return {"message": "The market is in trading."}265                tmp_df = tmp_df.iloc[-1]266                last_date = str(tmp_df["time"])267                newest_record = \268                    collection.find_one(sort=[("_id", DESCENDING)])269                if newest_record["time"] != last_date:270                    lst_symbols = list(newest_record.keys())[2:]271                    record = {}272                    record["time"] = last_date273                    for batch_idx in range(10):274                        str_symbols = ','.join(275                            lst_symbols[batch_idx*10:(batch_idx+1)*10])276                        data = requests.get('https://apipubaws.tcbs.com.vn/stock-insight/v1/stock/second-tc-price?tickers={}'.format(str_symbols)).json()277                        for i in data["data"]:278                            record[i["t"]] = i["rsi"]279                    collection.insert_one(record)280                    ret = "Updated data."281                else:282                    ret = "The data is up to date."283            else:284                ret = "The market is in trading."285            updating_rsi = False286            print(ret)287        except Exception as e:288            updating_rsi = False289            print(f"Caught error {e}.")290 291    @staticmethod292    def update_entire_rsi() -> None:293        global updating_rsi294        if updating_rsi:295            return {"message": "The data has been updating."}296        updating_rsi = True297        datetime_now = datetime.utcnow()298        hour = datetime_now.hour299        weekday = datetime_now.weekday()300        try:301            symbol_dict = Indicator.get_vn100(source="hsx")302            lst_symbols = symbol_dict["symbols"]303            if weekday < 5 and hour < 12:304                updating_rsi = False305                return {"message": "The market is in trading."}306            get_time = True307            lst_values = {}308            if len(lst_symbols) != 100:309                updating_rsi = False310                return {"message": "Not enough 100 symbols."}311            cnt = 0312            for symbol in lst_symbols:313                cnt += 1314                url = PREFIX + INDICATORS["RSI"] \315                    + f"?stockSymbol={symbol}&rangeSelector=3&periods=14"316                data = requests.get(url).json()317                rsi_df = pd.DataFrame(data["SeriesColection"][0]["Points"])318                if get_time:319                    lst_values["time"] = \320                        rsi_df["Time"].apply(lambda x:321                                             Utility.ts_to_date(x/1000))322                    get_time = False323                lst_values[symbol] = rsi_df["Value"].apply(lambda x: x[0])324            df = pd.DataFrame(lst_values)325            records = df.to_dict(orient="records")326            uri = os.environ.get("MONGODB_URI")327            client = MongoClient(uri)328            database = client.get_database("data")329            collection = database.get_collection("rsi")330            if "rsi" in database.list_collection_names():331                collection.drop()332            collection.insert_many(records)333            updating_rsi = False334            return {"message": "Updated data."}335        except Exception as e:336            updating_rsi = False337            return {"message": f"Caught error {e}."}338 339    @staticmethod340    def get_rsi(341        symbol: str,342        periods: int = 14,343        smooth_k: int = 3,344        smooth_d: int = 3,345    ) -> pd.DataFrame:346        try:347            symbol = symbol.upper()348            uri = os.environ.get("MONGODB_URI")349            client = MongoClient(uri)350            database = client.get_database("data")351            collection = database.get_collection("rsi")352            records = list(collection.find())353            record_df = pd.DataFrame(records).drop(columns=["_id"])354            record_df = \355                record_df[["time", symbol]].rename(columns={symbol: "rsi"})356            record_df["stoch_rsi"] = \357                Indicator.stoch_rsi(record_df["rsi"], periods)358            record_df["stoch_rsi_smooth_k"] = \359                Indicator.stoch_rsi_smooth_k(record_df["stoch_rsi"], smooth_k)360            record_df["stoch_rsi_smooth_d"] = Indicator.stoch_rsi_smooth_d(361                record_df["stoch_rsi_smooth_k"], smooth_d362            )363            return record_df364        except Exception as e:365            return pd.DataFrame(366                [{"message": f"Caught error {e}."}]367                )368 369    @staticmethod370    def stoch_rsi(rsi: pd.Series, periods: int = 14) -> pd.Series:371        ma, mi = (372            rsi.rolling(window=periods).max(),373            rsi.rolling(window=periods).min(),374        )375        return (rsi - mi) * 100 / (ma - mi)376 377    @staticmethod378    def stoch_rsi_smooth_k(stoch_rsi: pd.Series, k: int) -> pd.Series:379        return stoch_rsi.rolling(window=k).mean()380 381    @staticmethod382    def stoch_rsi_smooth_d(stoch_rsi_k: pd.Series, d: int) -> pd.Series:383        return stoch_rsi_k.rolling(window=d).mean()384 385    @staticmethod386    async def update_entire_macd() -> None:387        global updating_macd388        if updating_macd:389            print("The data has been updating.")390            return391        updating_macd = True392        datetime_now = datetime.utcnow()393        hour = datetime_now.hour394        weekday = datetime_now.weekday()395        try:396            symbol_dict = Indicator.get_vn100(source="hsx")397            lst_symbols = symbol_dict["symbols"]398            if weekday < 5 and hour < 12:399                updating_macd = False400                print("The market is in trading.")401                return402            get_time = True403            lst_values = {}404            if len(lst_symbols) != 100:405                updating_macd = False406                print("Not enough 100 symbols.")407                return408            cnt = 0409            for symbol in lst_symbols:410                cnt += 1411                url = PREFIX + INDICATORS["MACD"] \412                    + f"?stockSymbol={symbol}&rangeSelector=4&fastPeriod=12&slowPeriod=26&signalPeriod=9"413                data = requests.get(url).json()414                rsi_df = pd.DataFrame(415                    data["SeriesColection"][0]["Points"]).tail(20)416                if get_time:417                    lst_values["time"] = \418                        rsi_df["Time"].apply(lambda x:419                                             Utility.ts_to_date(x/1000))420                    get_time = False421                lst_values[symbol] = rsi_df["Value"].apply(lambda x: int(x[0]))422            df = pd.DataFrame(lst_values)423            records = df.to_dict(orient="records")424            uri = os.environ.get("MONGODB_URI")425            client = MongoClient(uri)426            database = client.get_database("data")427            collection = database.get_collection("macd")428            if "macd" in database.list_collection_names():429                collection.drop()430            collection.insert_many(records)431            updating_macd = False432            print("Updated data.")433        except Exception as e:434            updating_macd = False435            print(f"Caught error {e}.")436 437    @staticmethod438    def get_macd(439        symbol: str,440    ) -> pd.DataFrame:441        try:442            symbol = symbol.upper()443            uri = os.environ.get("MONGODB_URI")444            client = MongoClient(uri)445            database = client.get_database("data")446            collection = database.get_collection("macd")447            records = list(collection.find())448            record_df = pd.DataFrame(records).drop(columns=["_id"])449            record_df = \450                record_df[["time", symbol]].rename(columns={symbol: "macd"})451            return record_df452        except Exception as e:453            return pd.DataFrame(454                [{"message": f"Caught error {e}."}]455                )456 457    @staticmethod458    def get_ichimoku_cloud(459        df: pd.DataFrame,460        conversion_period=9,461        base_period=26,462        span_b_period=52,463        displacement=26,464    ) -> pd.DataFrame:465        space_displacement = np.full(displacement, np.nan)466        tenkan_sen = (467            df["high"].rolling(window=conversion_period).max()468            + df["low"].rolling(window=conversion_period).min()469        ) / 2470        kijun_sen = (471            df["high"].rolling(window=base_period).max()472            + df["low"].rolling(window=base_period).min()473        ) / 2474        senkou_span_a = (tenkan_sen + kijun_sen) / 2475        senkou_span_b = (476            df["high"].rolling(window=span_b_period).max()477            + df["low"].rolling(window=span_b_period).min()478        ) / 2479        chikou_span = df["close"].shift(-displacement)480 481        last_date = datetime.strptime(df["time"].iloc[-1], DATE_FORMAT)482        lst_date = Utility.generate_dates(last_date, displacement)483        time = np.concatenate((df["time"], lst_date))484        tenkan_sen = np.concatenate((tenkan_sen, space_displacement))485        kijun_sen = np.concatenate((kijun_sen, space_displacement))486        senkou_span_a = np.concatenate((space_displacement, senkou_span_a))487        senkou_span_b = np.concatenate((space_displacement, senkou_span_b))488        chikou_span = np.concatenate((chikou_span, space_displacement))489 490        data_dict = {491            "time": time,492            "tenkan_sen": tenkan_sen,493            "kijun_sen": kijun_sen,494            "senkou_span_a": senkou_span_a,495            "senkou_span_b": senkou_span_b,496            "chikou_span": chikou_span,497            "tenkan_kijun": tenkan_sen - kijun_sen,498            "kumo_cloud": senkou_span_a - senkou_span_b499        }500        return pd.DataFrame(data_dict)501