Source code for pyqqq.data.daily

from typing import Dict, List, Optional
from pyqqq.utils.array import chunk
from pyqqq.utils.api_client import raise_for_status, send_request
from pyqqq.utils.local_cache import DiskCacheManager
from pyqqq.utils.logger import get_logger
import datetime as dtm
import pandas as pd
import pyqqq.config as c
import pytz

logger = get_logger(__name__)
dailyCache = DiskCacheManager("daily_cache")


[docs] @dailyCache.memoize() def get_all_ohlcv_for_date(date: dtm.date, adjusted: bool = True) -> pd.DataFrame: """ 주어진 날짜에 대한 모든 주식의 OHLCV(Open, High, Low, Close, Volume) 데이터를 조회합니다. 이 함수는 특정 날짜에 대한 모든 주식의 시가, 고가, 저가, 종가 및 거래량 데이터를 API를 통해 요청하고, 이를 pandas DataFrame 형태로 반환합니다. 반환된 DataFrame은 'code'를 인덱스로 사용합니다. 2018년 1월 1일 데이터 부터 조회 가능합니다. Args: date (dtm.date): 조회할 날짜. adjusted (bool): 수정주가 여부. 기본값은 True. Returns: pd.DataFrame: OHLCV 데이터를 포함하는 DataFrame. 'code' 컬럼은 DataFrame의 인덱스로 설정됩니다. DataFrame의 컬럼은 다음과 같습니다. - open (int): 시가. - high (int): 고가. - low (int): 저가. - close (int): 종가. - volume (int): 거래량. - value (int): 거래대금. - diff (int): 종가 대비 전일 종가의 차이. - diff_rate (float): 종가 대비 전일 종가의 변화율. Raises: HTTPError: API 요청이 실패했을 때 발생. Examples: >>> ohlcv_data = get_all_ohlcv_for_date(dtm.date(2023, 5, 8)) >>> print(ohlcv_data) open high low close volume value diff diff_rate code 000020 8710 8790 8710 8770 39019 341233350 60 0.69 000040 1052 1133 1047 1047 590401 632158688 8 0.77 000050 7740 7870 7700 7750 1445 11211730 10 0.13 000070 68300 68800 67400 67600 33358 2261622200 -800 -1.17 000075 54800 54900 54800 54800 177 9702400 -100 -0.18 ... """ if isinstance(date, dtm.datetime): date = date.date() url = f"{c.PYQQQ_API_URL}/domestic-stock/ohlcv/daily/all/{date}" r = send_request( "GET", url, params={ "adjusted": "true" if adjusted else "false", "current_date": dtm.date.today(), }, ) raise_for_status(r) data = r.json() cols = data["cols"] rows = data["rows"] if not rows: return pd.DataFrame() else: df = pd.DataFrame(rows, columns=cols) df = df.astype({"open": int, "high": int, "low": int, "close": int, "volume": int, "value": int, "diff": int, "diff_rate": float}) df.drop(columns=["date"], inplace=True) df.set_index("code", inplace=True) return df
[docs] def get_ohlcv_by_codes_for_period( codes: List[str], start_date: dtm.date, end_date: Optional[dtm.date] = None, adjusted: bool = True, ascending: bool = False, ) -> Dict[str, pd.DataFrame]: """ 지정된 코드 리스트와 기간에 대한 OHLCV 데이터를 조회합니다. 이 함수는 하나 이상의 주식 코드와 시작 날짜, 선택적으로 종료 날짜를 지정하여 해당 기간 동안의 OHLCV 데이터를 API를 통해 요청합니다. 반환된 데이터는 각 주식 코드별로 시가, 고가, 저가, 종가, 거래량을 포함하는 pandas DataFrame 객체들로 구성된 딕셔너리 형태로 제공됩니다. 각 DataFrame은 해당 주식의 날짜를 기반으로 역순으로 정렬됩니다. 2018년 1월 1일 데이터 부터 조회 가능합니다. Args: codes (List[str]): 조회할 주식 코드들의 리스트. start_date (dtm.date): 조회할 기간의 시작 날짜. end_date (Optional[dtm.date]): 조회할 기간의 종료 날짜. 지정하지 않으면 최근 거래일 까지 조회됩니다. adjusted (bool): 수정주가 여부. 기본값은 True. ascending (bool): 날짜 오름차순 여부. 기본값은 False. Returns: dict: 주식 코드를 키로 하고, 해당 코드의 OHLCV 데이터를 포함하는 DataFrame을 값으로 하는 딕셔너리. DataFrame의 컬럼은 다음과 같습니다. - open (int): 시가. - high (int): 고가. - low (int): 저가. - close (int): 종가. - volume (int): 거래량. - value (int): 거래대금. - diff (int): 종가 대비 전일 종가의 차이. - diff_rate (float): 종가 대비 전일 종가의 변화율. Raises: HTTPError: API 요청이 실패했을 때 발생. Examples: >>> dfs = get_ohlcv_by_codes_for_period(['005930', '319640'], dtm.date(2024, 5, 7), dtm.date(2024, 5, 9)) >>> print(dfs) {'319640': open high low close volume value diff diff_rate date 2024-05-09 15380 15445 15365 15430 16200 249577480 -5 -0.03 2024-05-08 15445 15460 15365 15435 6419 99007660 -5 -0.03 2024-05-07 15355 15525 15355 15440 22318 345280470 85 0.55, '005930': open high low close volume value diff diff_rate date 2024-05-09 81100 81500 79700 79700 18700919 1504404274500 -1600 -1.97 2024-05-08 80800 81400 80500 81300 12960682 1050108654400 0 0.00 2024-05-07 79600 81300 79400 81300 26238868 2112619288066 3700 4.77} """ tz = pytz.timezone("Asia/Seoul") chunks = chunk(codes, 20) result = {} for i, asset_codes in enumerate(chunks): url = f"{c.PYQQQ_API_URL}/domestic-stock/ohlcv/daily/series" params = { "codes": ",".join(asset_codes), "start_date": start_date, "adjusted": "true" if adjusted else "false", "current_date": dtm.date.today(), } if end_date is not None: params["end_date"] = end_date r = send_request("GET", url, params=params) raise_for_status(r) data = r.json() cols = data["cols"] dataset = data["rows"] for code in dataset.keys(): rows = dataset[code] for row in rows: dt = row[0] if dt[-1] == "Z": dt = dt[:-1] + "+00:00" dt = dtm.datetime.fromisoformat(dt).astimezone(tz).replace(tzinfo=None) row[0] = dt rows.reverse() df = pd.DataFrame(rows, columns=cols) df = df.astype( { "open": int, "high": int, "low": int, "close": int, "volume": int, "value": int, "diff": int, "diff_rate": float } ) df.set_index("date", inplace=True) df.sort_index(ascending=ascending, inplace=True) result[code] = df return result