2021년 8월 30일 월요일

키움증권 Open API+

 

키움증권에서 제공하는 Open API+를 이용해서 주가 정보를 얻어 보려고 합니다.  아래는 키움증권에 제공하는 서비스 목록입니다.



키움증권의 Open API 소개는 다음 link에 있습니다.

https://www.kiwoom.com/h/customer/download/VOpenApiInfoView

 

컴퓨터 언어로 된 프로그램으로 접속하기 전에 먼저 KOA studio(키움증권 제공)로 접속되는지 아래 순서로 테스트해봐야 합니다.

 

1단계 openAPI 신청

2단계 OpenAPI+ 모듈 다운로드 및 설치

3단계 상시모의투자 신청

4단계 KOA studio 설치 및 접속 테스트

 

개발언어에는 원래 파이썬이 포함하지 않지만 PyQt5 pykiwoom 패키지를 사용하면 파이썬 프로그램도 가능합니다.  pykiwoomPyQt5보다 간단해서 여기서는 pykiwoom를 이용합니다.  

 

키움증권 Open API+를 써보니 몇 가지 제약점이 있습니다.

1) 키움증권 Open API+ 자체가 32비트입니다. 거래대금과 같은 데이터가 21억를 넘으면 32비트에서는 오류가 생길 수 있습니다.  파이썬 운영 환경도 64비트는 안되고 32비트 환경에 맞추어야 합니다.

2) 파이썬 패키지도 키움증권 Open API+를 기반으로 합니다. Open API+ MS 원도우에서만 실행할 수 있기 때문에 파이썬도 MS 원도우에서만 가능합니다.  파이썬 프로그램 실행에도 로그인 및 파일 다운로드 화면을 거쳐야 합니다.  버전 처리와 같은 에러도 여전히 볼 수 있는데 아래 블로그에 소개된 대로 요령이 필요합니다.

https://chancoding.tistory.com/102


3) 프로그램 운영 중에 접속 차단이 되는 경우 있습니다. 300개 종목에 대해 거래 정보를 취합하다가 과도한 요청이라고 하면서 중단이 되는 경우가 있었습니다. 조회 시간 간격을 늘려도 에러가 발생하는 것으로 보아 일정 시간 동안 조회 횟수가 아닌 데이터 양으로 조절하는 것 같습니다.  



과도한 요청으로 프로그램 실행이 중단되면 중단된 다음 종목부터 다시 조회할 수 있도록 프로그램 운영이 필요하겠습니다.

 

이 프로그램은 약 5년 동안 KRX300에 나오는 298개 종목에 대해 5년간 주가와 거래량을 조회합니다.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
from pykiwoom.kiwoom import *
import time
import pandas as pd
import csv

# 로그인
kiwoom = Kiwoom()
kiwoom.CommConnect(block=True)

# TR 요청 (연속조회)
with open("data_4232_20210828.csv", 'r') as csvfile:
    reader = csv.reader(csvfile)
    next(reader)
    for line in reader:
        code = line[0]
        print("\n", code, line[1], end=" ")
            
        dfs = []
        df = kiwoom.block_request("opt10015",
                          종목코드=code,
                          시작일자="20210827",
                          output="일별거래상세요청",
                          next=0)
        dfs.append(df)
        count = 1
        while kiwoom.tr_remained:
            df = kiwoom.block_request("opt10015",
                              종목코드=code,
                              시작일자="20210827",
                              output="일별거래상세요청",
                              next=2)
            dfs.append(df)
            print(count, end=" ", flush=True)
            time.sleep(1)
            count += 1
            if count >= 12:
                break
    

        pd_dfs = pd.concat(dfs)
        filename = code + ".csv"
        pd_dfs.to_csv(filename)


라인 31next=2는 해당 종목의 주가 기록이 있을 때까지 예전 모든 기록을 찾아 보여 줍니다. 5년 기록은 루프를 12번 정도 실행하면 모을 수 있습니다.  변수 next1 혹은 0으로 바꾸면 첫번째 호출 데이터(시작일자로 지정한 날로부터 과거 99일 동안의 주가 기록)만 반복적으로 나옵니다.  

 KRX300 종목은 아래 link에서 csv 혹은 excel 파일로 다운로드 가능합니다.  파일 data_4232_20210823.csv도 다운로드 받은 그대로입니다.

http://data.krx.co.kr/contents/MDC/MDI/mdiLoader/index.cmd?menuId=MDC0201010105

 

이렇게 모은 주식 데이터는 주식 분할을 고려하지 않습니다. 증권회사 HTS나 포털은 분할을 고려해서 주가를 보여주지만 원본 주가 정보는 이점을 고려하지 않습니다. 주식 분할, 합병 등이 있으면 주가가 갑자기 5분의 1로 떨어질 때가 있습니다. 아래 프로그램은 하루만에 주가가 2배 이상 뛰거나 반대로 1/2로 줄어들 때 날짜와 전날 주가 비율을 출력해 봅니다.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import glob
import csv

for fn in glob.glob("주가_거래/*.csv"):
    with open(fn, encoding='utf-8') as csvfile:
        reader = csv.reader(csvfile)
        next(reader) # skip header
        line = next(reader)
        prev = float(line[2].replace("+", "").replace("-", ""))
        for line in reader:
            try:
                price = float(line[2].replace("+", "").replace("-", ""))
                if price/prev > 2.0 or price/prev < 0.5:
                    print(fn, line[1], prev/price)
                prev = price
            except ValueError:
                print(fn)
                print(line)
                exit(1)


합병으로 인해 주가가 0.6으로만 줄어 들거나 1.4 정도만 오르면 찾아 내지 못하는 약점이 프로그램에 있습니다.  합병 등으로 주식이 하루 혹은 이틀 거래되지 않을 테니 거래량이 0인 시점을 찾아 주가를 보정하는 절차가 후에 필요하겠습니다.

 

일단 주가 비율이 크게 변동이 있었던 시점을 기준으로 찾은 주식 분할 혹은 합병이 있었던 종목별 파일과 날짜입니다. 아래 언급된 주가 보정 프로그램의 입력 파일인 to-adjust.txt 파일이기도 합니다.



298개 중에 약 10% 32개 종목에서 주식 분할 혹은 합병이 있었습니다. 1/5로 간단하게 분할되는 주식도 있고 간단한 비율은 아니지만 오리온홀딩스는 0.034, 효성은 0.3928 등은 과거 뉴스 기사에서 확인할 수 있습니다. 그런데  2017년에 롯데제과가 인적 분할하고 롯데쇼핑, 롯데칠성, 롯데푸드 투자 부문을 합쳐 롯데 지주를 만들 때는 비율이 어떻게 되는지 도저히 찾을 수가 없습니다. 주가를 보정하는 일반적인 방법이 필요합니다.


종목코드 004990, 롯데지주 주가 정보 일부입니다.  합병 전 20171027166,000(파란색)이었는데 합병후 20171030일 종가는 70,400(적색)입니다. 전일(영업일 기준) 대비 +6,400(노란색) 올랐으니 전일(27) 종가는 70400-6400, 64,000원으로 추정합니다. 27일 다음부터는 64000/166000=0.3855 비율로 주가를 보정합니다.    다음 프로그램이 주식 분할과 병합으로 인해 생긴 주가 변화를 보정합니다.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import shutil
import csv

fa = open("to-adjust.txt")
while True:
    line = fa.readline()
    if not line: break
    args = line.split(" ")
    shutil.copy(args[0], "original")
    fn = args[0].split("/")[1]
    fw = open(fn, mode='wt')
    change = False
    with open(args[0], encoding='utf-8') as csvfile:
        reader = csv.reader(csvfile)
        record = next(reader) # skip header
        fw.write(record[0]+","+record[1]+","+record[2]+","+record[3]+","+record[4]+","+record[5]+","+record[6]+"\n")
        record = next(reader)
        ratio = 1.0
        delta = int(record[4])
        price = int(record[2].replace("-", ""))
        fw.write(record[0]+","+record[1]+","+record[2]+","+record[3]+","+record[4]+","+record[5]+","+record[6]+"\n")
        for record in reader:
            if change == False and args[1] == record[1]:
                change = True
                ratio = float(record[2].replace("-", "")) / (price - delta)
            price = round(int(record[2].replace("-","")) / ratio)
            delta = round(int(record[4]) / ratio)
            amount = round(int(record[6]) * ratio)
            fw.write(record[0]+","+record[1]+","+str(price)+","+record[3]+","+str(delta)+","+record[5]+","+str(amount)+'\n')

    fw.close()

        


record는 일련번호,날짜,종가,전일대비기호,전일대비,등략율,거래량 순으로 데이터를 가지고 있습니다.

댓글 없음:

댓글 쓰기