본문 바로가기
주식 데이터 분석

[Python] 국내 주식 상한 VI를 카운팅해서 관련주 찾기

by HanYaung 2022. 5. 2.

같은 테마주들을 보면 같은 날 상한 VI가 걸리는 경우가 많더군요.

그래서 각각의 종목들이 같은날 상한 VI가 걸리는 날을 카운팅해서 관련주를 찾아보려고 합니다. 

- 동적 VI 발동 : 개별종목 직전 체결가에서 2~3% 이상 변동이 발생하는 경우

- 정적 VI 발동 : 종목별 전일 종가 기준으로 10% 이상 변동이 발생하는 경우

 

VI가 걸린 종목들을 가져오는 방법을 모르기 때문에 저는 전일 종가대비 당일 고가가 10프로 이상일 경우를 상한 VI가 걸렸다고 가정하고 카운팅하겠습니다.

 

2022.05.02 - [데이터로 보는 주식] - [Python] 주식 종목 간 상관관계 분석해서 관련주 찾기

1.  국내 주식들 가격 가져오기 

우선 국내 주식들의 주가를 가져와야합니다. 

키움증권 api로 주가를 가져오는게 가장 깔끔하겠지만 개발환경이 맥북임으로 다른 방법을 사용하겠습니다. 

저는 사용하기 편한 pykrx api를 사용하여 주가를 가져오겠습니다.( https://github.com/sharebook-kr/pykrx 

모든 종목의 2021년 05월 01부터 2022년 05 01일까지 1년 주가를 종가와 고가만 가져와 dataframe으로 만들겠습니다. 

def get_stock_price2(start_day, end_day):
    print("start get_stock_price")

    def str_day(d):
        return d.strftime('%Y%m%d')

    # 입력한 기간동안에 개장일을 구하기
    tmpDays = stock.get_market_ohlcv(start_day, end_day, "005930")
    days = list(map(str_day, tmpDays.index.to_list()))
    tmp = stock.get_market_ohlcv(days[0], market="ALL")
    # 종가와 고가를 "종가,고가" 형식으로 합치겠습니다.
    tmp["종고"] = tmp["종가"].map(str) + "," + tmp["고가"].map(str)
    viPrice = tmp["종고"].to_frame(name=days[0]).T

    for day in tqdm(days[1:]):
        ddf = stock.get_market_ohlcv(day, market="ALL")
        # vi
        ddf["종고"] = ddf["종가"].map(str) + "," + ddf["고가"].map(str)
        tmp_vi = ddf["종고"].to_frame(name=str(day)).T
        viPrice = pd.concat([viPrice, tmp_vi])

    def removeNull(df_stock):
        df_stock = df_stock.fillna(method='ffill')
        df_stock = df_stock.fillna(method='bfill')
        # df_stock = df_stock.dropna(axis=0)
        df = stock.get_market_ohlcv(days[-1], market="KOSPI")
        df2 = stock.get_market_ohlcv(days[-1], market="KOSDAQ")
        codeList = df.loc[df["저가"] != 0].index.tolist() + df2.loc[df2["저가"] != 0].index.tolist()
        df_stock = df_stock[codeList]

        def codeChangeName(code):
            name = stock.get_market_ticker_name(code)
            return name

        df_code = df_stock.columns.tolist()
        df_stock.columns = list(map(codeChangeName, df_code))
        return df_stock

    vi = removeNull(viPrice)
    vi.to_csv("stockPrice2.csv", mode='w')
get_stock_price2("20210501", "20220501")
print(pd.read_csv("stockPrice2.csv", dtype=str, index_col=0))
             AJ네트웍스        AK홀딩스        BGF  ...     흥국에프엔비         희림           힘스
20210503  5760,5980  30250,31550  6960,7060  ...  4220,4340  8200,8440  12800,13200
20210504  5820,5890  30000,30750  6900,6980  ...  4205,4280  8670,8760  13050,13050
20210506  5890,5950  32300,32550  7110,7130  ...  4205,4255  8640,8780  13100,13200
20210507  5910,5940  32900,33400  7060,7110  ...  4295,4320  9020,9130  13250,13300
20210510  6140,6240  34700,35000  7240,7290  ...  4255,4315  9360,9360  13250,13350
...             ...          ...        ...  ...        ...        ...          ...
20220425  6630,6750  22100,22600  5610,5690  ...  4570,4720  7770,8080    8960,9170
20220426  6660,6740  22100,22300  5630,5690  ...  4605,4855  8140,9000    9090,9100
20220427  6660,6660  21300,21600  5580,5630  ...  4440,4750  8500,8850    9030,9040
20220428  6640,6750  21100,21500  5650,5710  ...  4445,4625  8510,8930    8920,9050
20220429  6650,6650  21500,21700  5690,5710  ...  4375,4470  8640,8860    9030,9040

 

2. 상한 VI 카운팅하기 

def get_vi_count():
    print("start get_vi_count")
    vi = pd.read_csv("stockPrice2.csv", dtype=str, index_col=0)
    dic = dict.fromkeys(vi.columns, dict.fromkeys([str(i) for i in range(1, len(vi.columns) + 1)], ""))
    viDic = {}
    for dayId in (range(1, vi.shape[0])):
        yDay = vi.iloc[dayId - 1]
        tDay = vi.iloc[dayId]
        viList = []
        for codeId in range(vi.shape[1]):
            yDayCPrice = yDay.iloc[codeId].split(",")[0]
            tDayHPrice = tDay.iloc[codeId].split(",")[1]
            #전날 가격보다 오늘 가격이 10프로 이상오른경우
            if int(tDayHPrice) / int(yDayCPrice) > 1.1 and yDay.iloc[codeId] != tDay.iloc[codeId]:
                viList.append(vi.columns[codeId])
                viDic[vi.index[dayId]] = viList
    permut = []
    for key in tqdm(viDic.keys()):
        p = list(itertools.product(viDic[key], repeat=2))
        # p = list(itertools.permutations(viDic[key], 2))
        permut.extend(p)
    per = Counter(permut)

    df = pd.DataFrame(index=vi.columns, columns=vi.columns)
    df = df.fillna(0)
    for key, value in tqdm(per.items()):
        df.loc[key[0], key[1]] += int(value)
    df.to_csv("viCount.csv", mode='w')

    return df
# get_vi_count()
def search_viCount(stockName):
    vi = pd.read_csv("viCount.csv", dtype=str, index_col=0)
    result = vi.loc[stockName].astype(int).sort_values(ascending=False).head(10)
    print(result)
search_viCount("팜스토리")

데이터프레임을 2중 딕셔너리에 카운팅하여서 이를 다시 df으로 변환하였습니다. 

아래는 현대사료가 같은날 상한 VI가 같이 걸린 날을 카운팅한 것입니다.

현대사료         29
한일사료         17
팜스토리         13
일동홀딩스        13
에디슨INNO      12
미래생명자원       12
지에스이         11
중앙에너비스       10
하이스틸         10
이스트아시아홀딩스     9

사료 관련주 현대 사료입니다. 기존에 상관계수로 관련주를 찾는거 보다 훨씬 좋은 성능을 보여줍니다.

위에 현대사료 같은경우 사료로 묶인 한일사료, 팜스토리, 미래생명자원이 상위권에있습니다

저같은 경우 이걸 보고 현대사료와 한일사료가 계속 상을 치길래  비교적 덜 오른 팜스토리를 4월 초에 샀었고

4월 19일에 10프로 먹고 팔았슴돠. 

근데 오늘 보니까 4월 25~27일 따따따상 간거 보니 매우 배가 아프네여 ㅎㅎ

 

 

우진        25
일진파워      15
서전기전      14
에너토크      13
한신기계      13
두산2우B     12
우리기술      11
보성파워텍     10
비에이치아이     9

원전 관련주 우진 입니다. 상당히 좋은 성능을 보여줍니다. 신기하네요 

NE능률      27
덕성우       17
덕성        15
웹스        14
서연        13
위즈코프      13
웅진        12
노루홀딩스우    11
동양3우B     11
아이비김영     10

윤석률 관련주 ne능률입니다. 이것도 꽤 정확합니다 

 

랩지노믹스     24
휴마시스      10
수젠텍       10
엑세스바이오     8
아이진        7
KG ETS     7
EDGC       6
인성정보       6
키네마스터      6
신풍제약우      6

코로나 자가진단키트 랩지노믹스입니다. 이것도 좋네요 

 

2. 전체 코드

def get_stock_price2(start_day, end_day):
    print("start get_stock_price")

    def str_day(d):
        return d.strftime('%Y%m%d')

    # 입력한 기간동안에 개장일을 구하기
    tmpDays = stock.get_market_ohlcv(start_day, end_day, "005930")
    days = list(map(str_day, tmpDays.index.to_list()))
    tmp = stock.get_market_ohlcv(days[0], market="ALL")
    # 종가와 고가를 "종가,고가" 형식으로 합치겠습니다.
    tmp["종고"] = tmp["종가"].map(str) + "," + tmp["고가"].map(str)
    viPrice = tmp["종고"].to_frame(name=days[0]).T

    for day in tqdm(days[1:]):
        ddf = stock.get_market_ohlcv(day, market="ALL")
        # vi
        ddf["종고"] = ddf["종가"].map(str) + "," + ddf["고가"].map(str)
        tmp_vi = ddf["종고"].to_frame(name=str(day)).T
        viPrice = pd.concat([viPrice, tmp_vi])

    def removeNull(df_stock):
        df_stock = df_stock.fillna(method='ffill')
        df_stock = df_stock.fillna(method='bfill')
        # df_stock = df_stock.dropna(axis=0)
        df = stock.get_market_ohlcv(days[-1], market="KOSPI")
        df2 = stock.get_market_ohlcv(days[-1], market="KOSDAQ")
        codeList = df.loc[df["저가"] != 0].index.tolist() + df2.loc[df2["저가"] != 0].index.tolist()
        df_stock = df_stock[codeList]

        def codeChangeName(code):
            name = stock.get_market_ticker_name(code)
            return name

        df_code = df_stock.columns.tolist()
        df_stock.columns = list(map(codeChangeName, df_code))
        return df_stock

    vi = removeNull(viPrice)
    vi.to_csv("stockPrice2.csv", mode='w')
# get_stock_price2("20210501", "20220501")
# print(pd.read_csv("stockPrice2.csv", dtype=str, index_col=0))


def get_vi_count():
    print("start get_vi_count")
    vi = pd.read_csv("stockPrice2.csv", dtype=str, index_col=0)
    dic = dict.fromkeys(vi.columns, dict.fromkeys([str(i) for i in range(1, len(vi.columns) + 1)], ""))
    viDic = {}
    for dayId in (range(1, vi.shape[0])):
        yDay = vi.iloc[dayId - 1]
        tDay = vi.iloc[dayId]
        viList = []
        for codeId in range(vi.shape[1]):
            yDayCPrice = yDay.iloc[codeId].split(",")[0]
            tDayHPrice = tDay.iloc[codeId].split(",")[1]
            #전날 가격보다 오늘 가격이 10프로 이상오른경우
            if int(tDayHPrice) / int(yDayCPrice) > 1.1 and yDay.iloc[codeId] != tDay.iloc[codeId]:
                viList.append(vi.columns[codeId])
                viDic[vi.index[dayId]] = viList
    permut = []
    for key in tqdm(viDic.keys()):
        p = list(itertools.product(viDic[key], repeat=2))
        # p = list(itertools.permutations(viDic[key], 2))
        permut.extend(p)
    per = Counter(permut)

    df = pd.DataFrame(index=vi.columns, columns=vi.columns)
    df = df.fillna(0)
    for key, value in tqdm(per.items()):
        df.loc[key[0], key[1]] += int(value)
    df.to_csv("viCount.csv", mode='w')

    return df
# get_vi_count()
def search_viCount(stockName):
    vi = pd.read_csv("viCount.csv", dtype=str, index_col=0)
    result = vi.loc[stockName].astype(int).sort_values(ascending=False).head(10)
    print(result)
search_viCount("랩지노믹스")

코드나 데이터가 잘못될 수도 있으니 투자에 참고만 해야겠지만 꽤 의미있는 정보인거 같습니다