'pykrx' 태그의 글 목록 :: Horizontal Grays S2

 

책을 아직도 다 읽진 않았지만 - 앞으로도 다 읽진 않겠지만 - 

매수종목 선정 방법 관련해서는 자세히 나온것이 없다. 

그래서 임의로 내가 방법을 세우고 프로그래밍해려고 한다.

 

검색해보면 이러한 종목이 오를 것이다라는 여러 이야기 들이 있지만 복잡한것까지는 잘 모르겠다.

내 경험상으로도 그렇고 검색 결과로도 그렇고 일단 거래량이 가장 중요한 것 같다.

그래서 일단 단순하게

 

1. 이틀전 거래량 - 하루전 거래량 으로 거래량 증가폭이 높은 순으로 정렬해서 최상단 20종목 추리고

2. 그중 하루전 거래량 기준으로 절대 거래량 높은 순으로 10종목 추려서 매수종목 리스트에 넣는다.

 

이런 단순한 방법을 우선 취해보기로 했다. 

이렇게 한 근거는 일단 없다. 이렇게 해보고 결과가 안좋으면 수정해야겠다.

 

크레온 플러스 API 예제를 이용하면 더 편할것 같기도 한데 이게 제한이 있다.

   조회 제한  실시간 제한
시세
오브젝트
15초에 최대 60건으로제한
초과 요청시 첫 요청으로부터 15초가
지날 때까지 내부적으로기다림
최대 400건의요청으로제한
초과요청시오류
주문관련오브젝트 15초에 최대 20건으로제한
초과 요청시 첫 요청으로부터 15초가
지날 때까지 요청함수(Request, BlockRequest, BlockRequest2)에서
4를 반환
제한 없음

그래서 일단 네이버 스크래핑을 위주로 이용해보기로 한다.

 

먼저 처음 예제였던 종목정보 구하기 예제를 차후에 파일로 가공할 것을 감안하여 조금 수정하고

실행해서 전체종목의 코드를 구해봤다. (이건 크레온 플러스 API 이용)

 

import win32com.client

# 연결 여부 체크
objCpCybos = win32com.client.Dispatch("CpUtil.CpCybos")
bConnect = objCpCybos.IsConnect
if (bConnect == 0):
    print("PLUS가 정상적으로 연결되지 않음. ")
    exit()
 
# 종목코드 리스트 구하기
objCpCodeMgr = win32com.client.Dispatch("CpUtil.CpCodeMgr")
codeList = objCpCodeMgr.GetStockListByMarket(1) #거래소
codeList2 = objCpCodeMgr.GetStockListByMarket(2) #코스닥
 
 
print("번호",",","종목코드",",","종목명",",","구분코드",",","금액")
for i, code in enumerate(codeList):
    secondCode = objCpCodeMgr.GetStockSectionKind(code)
    name = objCpCodeMgr.CodeToName(code)
    stdPrice = objCpCodeMgr.GetStockStdPrice(code)
    print(i,",",code,",", name,",", secondCode,",", stdPrice)
    
for i, code in enumerate(codeList2):
    secondCode = objCpCodeMgr.GetStockSectionKind(code)
    name = objCpCodeMgr.CodeToName(code)
    stdPrice = objCpCodeMgr.GetStockStdPrice(code)
    print(i+len(codeList),",",code,",", name,",", secondCode,",", stdPrice)
 
#print("거래소 + 코스닥 종목코드 ",len(codeList) + len(codeList2))

실행할 때 단지 아래와 같이 하면 print 결과값을 파일로 저장한다.

python test1.py > codelist.txt

 

이로써 codelist.txt라는 종목정보파일이 만들어졌다.

이 파일의 끝을 보면 "거래소 + 코스닥 종목코드  3306" 으로 총 3306 종목이 있슴을 알 수 있고

위 그림과 같이 ETF도 포함되어 있슴을 알 수 있다. 

 

이 txt파일을 엑셀에서 읽어서 금일거래량, 전일거래량, 거래량증가비 열을 추가하고 codelist.xlsx 로 저장했다.

 

우선 파이썬에서 엑셀 데이터를 다루기 위해서 openpyxl을 설치해주도록 한다.

pip install openpyxl을 cmd 창에서 실행

 

 

-----------------------------------------------------------------------------------------------------------------------------------

이렇게 하다가 문제가 발생했다.

여튼 엑셀데이터의 종목코드를 읽고 거래량을 구하는 과정에서 현재 거래정지된 종목의 경우 에러가 발생하는 것이었다.

여기서 예외처리를 할까 하다가 전면 수정을 하기로 하고 다시 프로그램을 작성했다.

종목코드 자체를 매일 실시간으로 읽어서 진행하기로...

 

검색해보니 pykrx 라고 주식관련 라이브러리가 아주 잘되어 있었고 어차피  엑셀을 이용해도 이 라이브러리를 이용했어야 했다. ("GitHub - sharebook-kr/pykrx: KRX 주식 정보 스크래핑" 참고)

 

기본적인 구상은 다음과 같다.

매일 장을 종료하면 이 프로그램을 실행하여

1. 종목코드를 get_market_ticker_list() 로 읽어와서

2. get_market_ohlcv_by_date() 로 거래량 정보를 읽고 가공 후 DataFrame에 집어넣고

3. 각 DataFrame을 거래량 별로 정렬 후 상위 추출, 거래량 변화율 별로 정렬 후 상위 추출

4. ETF는 70%, KOSPI/KOSDAQ에서는 30%로 구성해서 20개 종목을 최종 List 만들어서

5. 파일로 저장

6. 다음날 자동거래 프로그램에서 매수대상 리스트는 이 파일을 읽어서 20개의 후보군으로 실행

 

파이썬을 잘 모르기도 하고 혼자서 단순하게 막 짜다보니 좀 비효율적인 프로그램이 된것 같긴 하지만 일단 테스트로 돌려본 결과 잘 돌아가긴 한다.

 

내일 자동거래 프로그램을 백테스팅용으로 수정을 좀 하고 목,금 백테스팅을 좀 하고 4월부터는 실제거래를 해봐야겠다.

 

 

from pykrx import stock
import time,sys
import pandas as pd
from datetime import datetime,timedelta

#DataFrame define
kospi_stock_list = pd.DataFrame(columns=['stock_code','price','yesterday_volume','today_volume','volume_ratio'])
kosdaq_stock_list = pd.DataFrame(columns=['stock_code','price','yesterday_volume','today_volume','volume_ratio'])
etf_stock_list = pd.DataFrame(columns=['stock_code','price','yesterday_volume','today_volume','volume_ratio'])

today = datetime.today()- timedelta(0)      #오늘날짜 구하기 timedelta(1)을 빼면 어제날짜
yesterday = datetime.today()- timedelta(1)
str_today = today.strftime("%Y%m%d")        #구한 날짜를 String type으로
str_yesterday = yesterday.strftime("%Y%m%d")        #구한 날짜를 String type으로

print(str_today)
print(str_yesterday)
bt_day = stock.get_nearest_business_day_in_a_week(date=str_today)   #오늘 날짜 집어넣고 장을 여는 가장 가까운 날을 구함 오늘 장을 열면 오늘 날짜 반환
by_day = stock.get_nearest_business_day_in_a_week(date=str_yesterday)
print("btday=",bt_day)
print("byday=",by_day)
if bt_day != str_today: #오늘 날짜와 구한 날짜가 같지 않다는건 오늘 장을 열지 않는다는 것
    print("오늘은 장을 열지 않으므로 프로그램 종료")
    sys.exit(0)

kospilist = stock.get_market_ticker_list(date=bt_day, market="KOSPI")   #KOSPI 종목코드를 list로 반환
kosdaqlist = stock.get_market_ticker_list(date=bt_day, market="KOSDAQ") #KOSDAQ 종목코드를 list로 반환
etflist = stock.get_etf_ticker_list(date=bt_day)                        #ETF 종목코드를 list로 반환

kospi_stock_list_count = 0      #나중에 Dataframe에 count로 사용할 변수 초기화
kosdaq_stock_list_count = 0
etf_stock_list_count = 0

print("KOSPI 확인 - 종목수 : ",len(kospilist))
for kospi_ticker in kospilist:  #KOSPI 종목
#for i in range(100):   #for test
#    kospi_ticker = kospilist[i]    #for test
    df = stock.get_market_ohlcv_by_date(fromdate=by_day, todate=bt_day, ticker=kospi_ticker)    #KOSPI 종목코드 어제,오늘 관련정보 DataFrame

    yesterday_volume = df.iloc[0]['거래량']     #DataFrame에서 어제 거래량 변수로 입력
    today_volume = df.iloc[1]['거래량']         #DataFrame에서 오늘 거래량 변수로 입력
    today_price = df.iloc[1]['종가']            #DataFrame에서 오늘 종가 변수로 입력
    
    print("종목코드",kospi_ticker)
    print("종가",today_price) 
    print("어제 거래량",yesterday_volume)
    print("오늘 거래량", today_volume)
    if yesterday_volume == 0:                   #어제거래량이 없으면 거래량변화 -100
        volume_ratio = -100
    else:
        volume_ratio = (today_volume-yesterday_volume)/yesterday_volume     #거래량변화율 

    
    new_data = [kospi_ticker,today_price,yesterday_volume,today_volume,volume_ratio]
    kospi_stock_list.loc[kospi_stock_list_count] = new_data     #관련 정보 DataFrame의 행에 추가
    kospi_stock_list_count = kospi_stock_list_count + 1
    time.sleep(1) 

print("KOSDAQ 확인 - 종목수 : ",len(kosdaqlist))
for kosdaq_ticker in kosdaqlist:
#for i in range(100):       #for test
    #kosdaq_ticker = kosdaqlist[i]  #for test
    df = stock.get_market_ohlcv_by_date(fromdate=by_day, todate=bt_day, ticker=kosdaq_ticker)
    
    yesterday_volume = df.iloc[0]['거래량']
    today_volume = df.iloc[1]['거래량']
    today_price = df.iloc[1]['종가']
    
    print("종목코드",kosdaq_ticker)
    print("종가",today_price) 
    print("어제 거래량",yesterday_volume)
    print("오늘 거래량", today_volume)
    if yesterday_volume == 0:
        volume_ratio = -100
    else:
        volume_ratio = (today_volume-yesterday_volume)/yesterday_volume

    
    new_data = [kosdaq_ticker,today_price,yesterday_volume,today_volume,volume_ratio]
    kosdaq_stock_list.loc[kosdaq_stock_list_count] = new_data
    kosdaq_stock_list_count = kosdaq_stock_list_count + 1
    time.sleep(1) 



print("ETF 확인 - 종목수 : ",len(etflist))
for etf_ticker in etflist:
#for i in range(100):   #for test
    #etf_ticker = etflist[i]    #for test
    df = stock.get_market_ohlcv_by_date(fromdate=by_day, todate=bt_day, ticker=etf_ticker)
    
    yesterday_volume = df.iloc[0]['거래량']
    today_volume = df.iloc[1]['거래량']
    today_price = df.iloc[1]['종가']
    
    print("종목코드",etf_ticker)
    print("종가",today_price) 
    print("어제 거래량",yesterday_volume)
    print("오늘 거래량", today_volume)
    if yesterday_volume == 0:
        volume_ratio = -100
    else:
        volume_ratio = (today_volume-yesterday_volume)/yesterday_volume

    
    new_data = [etf_ticker,today_price,yesterday_volume,today_volume,volume_ratio]
    etf_stock_list.loc[etf_stock_list_count] = new_data
    etf_stock_list_count = etf_stock_list_count + 1
    time.sleep(1) 

all_stock_list = pd.concat([kospi_stock_list,kosdaq_stock_list])    #KOSPI와 KOSDAQ은 합쳐서 하나의 DataFrame으로

print("KOSPI")
print(kospi_stock_list)
print("KOSDAQ")
print(kosdaq_stock_list)
print("KOSPI+KOSDAQ")
print(all_stock_list)
print("ETF")
print(etf_stock_list)


all_stock_list.sort_values(['today_volume'],axis=0,ascending=False,inplace=True)    #거래량 우선으로 정렬
sort_volume_list = all_stock_list.head(12)                                          #그중 12개만 추출해서 저장
print("all stock sort by volume")
print(sort_volume_list)
sort_volume_list.sort_values(['volume_ratio'],axis=0,ascending=False,inplace=True)  #12개를 거래량 변화율로 정렬
sort_ratio_list = sort_volume_list.head(6)                                          #그 중 6개만 추출해서 저장
print("all stock sort by volume")
print(sort_ratio_list)

etf_stock_list.sort_values(['today_volume'],axis=0,ascending=False,inplace=True)    #ETF도 같은 과정 
etf_sort_volume_list = etf_stock_list.head(28)
print("ETF stock sort by volume")
print(etf_sort_volume_list)
etf_sort_volume_list.sort_values(['volume_ratio'],axis=0,ascending=False,inplace=True)
etf_sort_ratio_list = etf_sort_volume_list.head(14)             
print("ETF stock sort by volume")
print(etf_sort_ratio_list)

total_stock_list = pd.concat([sort_ratio_list,etf_sort_ratio_list])     #최종 KOSPI,KOSDAQ에서 6개, ETF에서 14개 총 20개 를 하나의 DataFrame으로 합치고
print("Total stock sort by volume")
print(total_stock_list)

final_stock_list = list(total_stock_list['stock_code'])     #DataFrame에서 종목코드만 List로 뽑고
print("final Stock List")
print(final_stock_list)

for i in range(len(final_stock_list)):
    final_stock_list[i] = 'A'+ str(final_stock_list[i])     #List에 'A' 추가해서
print(final_stock_list)

f = open('codelist.txt','w')
f.write(','.join(final_stock_list))     #파일로 저장
f.close()

#symbol_list = open('codelist.txt','r').read().split(',')       #for verify
#print(symbol_list)                                             #for verify

+ Recent posts