키움 OPEN API 주식 자동화

 

 

이전 글 보러 가기

 

01_시작

02_기본설정

03_pykiwoom vs. 직접코딩

04_키움 open api 로그인 하기

05_키움 OPEN API에 TR 요청하기(feat. 예수금과 계좌잔고 받아오기)

06_키움 KOA 설치하기

07_키움 KOA 이해하기

08_키움 KOA 이해하기_2

09_키움 OPEN API 계좌평가 잔고 가져오기

10_키움 OPEN API 일봉데이터 가져오기_1

 

 

 

이전 글에서 일봉데이터를 가져오기 위한 배경에 대해 학습했다. 이제 코드에 대해 알아보자. 코드 작성을 위한 전반적인 도움은 지난 글에서 설명한 유튜브 "프로그램 동산" 채널을 도움을 받았다.

 

 

먼저 조회할 종목 리스트를 만들어보자. 앞서 살펴본 바와 같이 키움 KOA에서 종목정보 관련 함수인 "GetCodeListByMarket()"를 활용할 수 있다.

 

 

키움 KOA 종목 리스트 만들기(GetCodeListByMarket)

 

GetCodeListByMarket()는 시장 구분 값만 파라미터로 보내주면, 해당 시장의 종목코드를 세미콜론(';)으로 구분하여 보내준다.

 

 

"0 장내"는 거래소에 상장되어 있는 주식과 채권 등을 모두 의미한다. 코스피(KOSPI), 코스닥(KOSDAQ) 등을 모두 포함한다.

 

"10 코스닥"은 미국의 벤처기업으로 구성된 시장인 나스닥을 본떠 만든 시장으로 벤처기업과 유망 중소기업을 위한 시장이다.

 

3 ELW, 8 ETF, 50, KONEX, 4 뮤추얼펀드, 5, 신주인수권, 6, 리츠, 9 하이얼펀드, 30 K-OTC 는 아직 별 관심이 없어서 PASS. 

 

 

from PyQt5.QtTest import *  # 일봉조회 타이머 걸기

# 종목 목록 가져오기
def get_code_list_by_market(self, market_code):
    code_list = self.dynamicCall("GetCodeListByMarket(QString)", market_code)
    code_list = code_list.split(";")[:-1]
    return code_list

# 종목 분석 실행용 함수
def calculator_fnc(self):
    code_list = self.get_code_list_by_market("10") # 10: 코스탁
    print("코스닥 갯수 %s" % len(code_list))

    for idx, code in enumerate(code_list):
        self.dynamicCall("DisconnectRealData(QString)", "4000")  # 스크린 연결 끊기
        print("%s / %s : KOSDAQ Stock Code : %s is updating..." % (idx+1, len(code_list), code))
        self.day_kiwoom_db(code=code)
        
# 일봉 가져오기
def day_kiwoom_db(self, code=None, date=None, sPrevNext="0"):
    QTest.qWait(3600) # 3.6초 delay
    self.dynamicCall("SetInputValue(QString, QString)", "종목코드", code)
    self.dynamicCall("SetInputValue(QString, QString)", "수정주가구분", "1")

# date 빈값은 오늘. None이 아니면 날짜를 입력하도록
    if date != None:
        self.dynamicCall("SetInputValue(QString, QString)", "기준일자", date)
    self.dynamicCall("CommRqData(QString, QString, int, QString)", "주식일봉차트조회", "opt10081", sPrevNext, self.screen_calculation_stock) #TR 서버로 전송
        self.calculator_event_loop.exec_()

 

종목 목록을 가져오기 위한 함수를 "get_code_list_by_market"로 만들고, market_code를 GetCodeListByMarket() 함수로 넘겨준다. 앞서 살펴본 바와 같이 GetCodeListByMarket() 함수는 종목코드를 세미콜론(;)으로 구분하여 넘겨주므로, 세미콜론을 지우기 위해 ".split(";")"을 사용한다. 끝에 [:-1]을 해준 이유는 끝자리에 남아있는 세미콜론을 지워주기 위함이다.

 

"get_code_list_by_market" 함수는 code_list를 return 해 준다.

 

 

calculator_fnc 라는 함수를 만들어서 

1. 위에서 만든 "get_code_list_by_market" 함수에 market_code를 "10"으로 넘겨주고

2. code_list 개수를 프린트하고

3. code_list에서 하나씩 빼와서

4. DisconnectRealData로 스크린 연결을 끊어주고 (이건 안 해도 됨)

5. 진행 상황을 프린트하고

6. 가지고 있는 code_list 하나를 "day_kiwoom_db"로 보내준다.

 

 

"day_kiwoom_db"라는 함수를 만들어서

1. code는 위에서 만든 "calculator_fnc"에서 넘겨받고

2. date는 빈 값으로 두고(빈 값은 오늘을 의미함)

3. sPrevNext는 일단 0으로 설정 (0은 "이전" 버튼을 누르지 않는 것임)

4. Qtest.qwait(3600)으로 이번 조회 후 다음 조회하기까지 3.6초를 기다려 준다. 기다림 없이 조회하면 키움 서버 과부하 방지를 위해 오류를 반환한다.

5. CommRqData로 데이터를 요청한다.

6. calculator_event_loop를 실행해준다.

 

 

 

def trdata_slot(self, sScrNo, sRQName, sTrCode, sRecordName, sPrevNext):


    if sRQName == "주식일봉차트조회":
        code = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, 0, "종목코드")
        code = code.strip()
        print("%s 일봉데이터 요청" % code)

        # 조회된 row 출력
        cnt = self.dynamicCall("GetRepeatCnt(QString, QString)", sTrCode, sRQName)
        print(cnt)

        # 조회 자료 리스트 만들기
        # GetCommDataEx 매소드 사용 검토
        # data = self.dynamicCall("GetCommDataEx(QString, QString)", sTrCode, sRQName)
        # [['', '현재가', ...., '저가', ''] .... ['', '현재가', ...., '저가', '']]
        # [['', '현재가', '거래량', '거래대금', '날짜', '시기', '고가', '저가', '']]
        for i in range(cnt):
            data = []
            current_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "현재가") # 종가
            volume = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "거래량")
            trading_value = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "거래대금")
            date = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "일자")
            staring_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "시가")
            high_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "고가")
            low_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "저가")

			data.append("")
            data.append(current_price.strip())
            data.append(volume.strip())
            data.append(trading_value.strip())
            data.append(date.strip())
            data.append(staring_price.strip())
            data.append(high_price.strip())
            data.append(low_price.strip())
            data.append("")

			self.calcul_data.append(data.copy())

		print(len(self.calcul_data))
        
        
        # 일봉 600일 이상치 가져오기(페이지 넘기기)
        if sPrevNext == "2":
            self.day_kiwoom_db(code=code, sPrevNext=sPrevNext)
        else:
            print("총 일수 %s" % len(self.calcul_data))
            pass_success = False
        
            self.calculator_event_loop.exit()

 

 

trdata_slot 함수로 준비된 데이터를 활용해서 요청한다.

중간중간에 print를 활용해서 진행상황을 출력하도록 해야 오류 생성 시 디버깅이 가능하다.

 

일봉데이터를 요청하면 다음과 같은 리스트 형태로 반환된다.

[['', '현재가', '거래량', '거래대금', '날짜', '시기', '고가', '저가', '']]

 

반환된 값을 하나씩 data 리스트에 담아준다.

 

 

 

일봉을 조회하는 opt10081 TR은 한번 조회 시 600일치의 데이터를 보내준다. 600일 이전의 데이터를 가져오기 위해서는 sPrevNext를 "2"로 넘겨줘야 한다.

 

 

600일 이전의 데이터를 모두 받아왔으면, "calculator_event_loop"를 끊어준다.

 

 

 

파이썬을 학습하며 남기는 블로그입니다.
질문, 지적, 조언은 항상 환영합니다.

 

 

 

2021.01.18. 코리.

 

 

+ Recent posts