정보

[파이썬] 주식 자동 매매 시스템 구현 #5 - 종목 정보 가져오기

바다♬~♪ 2022. 3. 22. 10:46

파이썬을 모르는 내가 파이썬을 활용하여 키움 자동 매매 시스템을 구현하는 과정을 정리하고자 한다. 1인칭 시점으로 이해한걸 정리하는 것으로 혹시나 잘못 이해하고 정리된 부분이 있을 수 있다.

 

이제 로그인을 했으면 주가를 조회해야 하겠다. 다만 현재는 종목 코드 등 주가 조회를 위한 기본 정보를 알 수 없기에 종목 Master 정보 등을 가져오는 것을 먼저 해 보자.

 

1. 종목 코드 가져오기

기존 코드에서 종모고 정보 가져오는 부분만 수정하도록 한다.

종목 코드는 GetCodeListByMarket 함수를 사용한다.

 

기존의 kiwoom.py 파일에 다음 함수를 추가한다.

    def get_code_list_by_market(self, market_type):
        code_list = self.dynamicCall("GetCodeListByMarket(QString)", market_type)
        code_list = code_list.split(';')[:-1]
        return code_list

 

kiwoom.py 전체 코드

from PyQt5.QAxContainer import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *


class Kiwoom(QAxWidget):  # PyQt5 패키지의 QAxContainer 모듈에 있는 QAxWidget 클래스를 상속받아 Kiwoom 클래스 객체를 정의한다.

    def __init__(self):  # Kiwoom 클래스의 생성자 : Kiwoom 클래스 객체가 생성될 때 호출되어 내부 정의된 구문 실행
        super().__init__()  # 상속받은 QAxWidget 객체 초기화
        self.create_kiwoom_instance()  # 키움 인스턴스 생성
        self.comm_login()  # 키움 연결 설정 / 로그인 실행

    def create_kiwoom_instance(self):
        self.setControl("KHOPENAPI.KHOpenAPICtrl.1")  # Kiwoom Open API+를 설치하면서 registry에 등록된 값으로 Kiwoom 인스턴스 생성

    def comm_login(self):
        self.OnEventConnect.connect(self.login_slot)  # OnEventConnect 이벤트와 slot 을 메모리에 적재
        self.dynamicCall("CommConnect()")  # signal 함수 호출 (login)
        self.login_event_loop = QEventLoop()  # login event loop 정의
        self.login_event_loop.exec_()  # login event loop 실행

    def login_slot(self, err_code):  # OnEventConnect 함수의 return 값을 err_code로 받음
        if err_code == 0:
            print("login success")
        else:
            print("login failed")
        self.login_event_loop.exit()  # loging event loop 종료

    def get_login_info(self, info_type):
        return_value = self.dynamicCall("GetLoginInfo(QString)", info_type)
        if info_type == "ACCLIST":
            return_value = return_value.split(';')
        elif info_type == "ACCNO":
            return_value = return_value.split(';')[:-1]

        print(info_type, ": ", return_value)
        return return_value

    def get_code_list_by_market(self, market_type):
        code_list = self.dynamicCall("GetCodeListByMarket(QString)", market_type)
        code_list = code_list.split(';')[:-1]
        return code_list

 

main.py 에서 코드 정보를 얻고 출력하는 부분을 추가한다.

# get code list
kospi_code_list = kiwoom.get_code_list_by_market("0")
print("kospi_code_size: ", len(kospi_code_list))
print(kospi_code_list)

 

main.py 전체 코드

from api.kiwoom import *
import sys

# app 객체 생성
app = QApplication(sys.argv)
# import 한 Kiwoom class object 생성 (인스턴스화)
kiwoom = Kiwoom()

# get code list
kospi_code_list = kiwoom.get_code_list_by_market("0")
print("kospi_code_size: ", len(kospi_code_list))
print(kospi_code_list)

# app 객체의 exec_() 함수 실행
app.exec_()

 

다음과 같이 kospi 1,760 개에 대한 종목 코드가 출력된다.

종목 코드 출력 결과

 

시장 구분값을 조정하여 원하는 시장에 대한 종목 코드를 가져올 수 있다.

[시장구분값]
0 : 코스피
10 : 코스닥
3 : ELW
8 : ETF
50 : KONEX
4 :  뮤추얼펀드
5 : 신주인수권
6 : 리츠
9 : 하이얼펀드
30 : K-OTC

 

2. 종목 이름 가져오기

종목 이름을 가져오기 위해서는 GetMasterCodeName 함수를 이용한다. 해당 함수는 종목코드 한개 만을 파라미터로 받기 때문에 for loop 구문을 사용하여 앞서 받아온 코드 list 에서 개별 코드를 추출하여 활용한다.

 

기존 main.py, kiwoom.py 코드에 아래 두 코드를 추가한다.

 

main.py 에서 for loop 구문을 활용하여 종목명을 요청하는 코드

for code in kospi_code_list:
    code_name = kiwoom.get_master_code_name(code)
    print(code, ":", code_name)

 

kiwoom.py 에서 종목명을 가져오는 코드

    def get_master_code_name(self, code):
        code_name = self.dynamicCall("GetMasterCodeName(QString", code)
        return code_name

 

종목명이 잘 출력된 결과를 확인할 수 있다.

종목코드 / 종목명 출력 결과

 

향후에는 선물/옵션 관련해서도 만들거지만, 우선은 구현에 초점을 맞추어 kospi 종목명 가져오는 부분까지만 정리했다.

나머지도 아래 종목정보 관련 함수를 참조하면 쉽게 구현이 가능하다.

 

main.py 전체 코드

from api.kiwoom import *
import sys

# app 객체 생성
app = QApplication(sys.argv)
# import 한 Kiwoom class object 생성 (인스턴스화)
kiwoom = Kiwoom()

# get code list
kospi_code_list = kiwoom.get_code_list_by_market("0")
print("kospi_code_size: ", len(kospi_code_list))
print(kospi_code_list)

for code in kospi_code_list:
    code_name = kiwoom.get_master_code_name(code)
    print(code, ":", code_name)


# app 객체의 exec_() 함수 실행
app.exec_()

 

kiwoom.py  전체 코드

from PyQt5.QAxContainer import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *


class Kiwoom(QAxWidget):  # PyQt5 패키지의 QAxContainer 모듈에 있는 QAxWidget 클래스를 상속받아 Kiwoom 클래스 객체를 정의한다.

    def __init__(self):  # Kiwoom 클래스의 생성자 : Kiwoom 클래스 객체가 생성될 때 호출되어 내부 정의된 구문 실행
        super().__init__()  # 상속받은 QAxWidget 객체 초기화
        self.create_kiwoom_instance()  # 키움 인스턴스 생성
        self.comm_login()  # 키움 연결 설정 / 로그인 실행

    def create_kiwoom_instance(self):
        self.setControl("KHOPENAPI.KHOpenAPICtrl.1")  # Kiwoom Open API+를 설치하면서 registry에 등록된 값으로 Kiwoom 인스턴스 생성

    def comm_login(self):
        self.OnEventConnect.connect(self.login_slot)  # OnEventConnect 이벤트와 slot 을 메모리에 적재
        self.dynamicCall("CommConnect()")  # signal 함수 호출 (login)
        self.login_event_loop = QEventLoop()  # login event loop 정의
        self.login_event_loop.exec_()  # login event loop 실행

    def login_slot(self, err_code):  # OnEventConnect 함수의 return 값을 err_code로 받음
        if err_code == 0:
            print("login success")
        else:
            print("login failed")
        self.login_event_loop.exit()  # loging event loop 종료

    def get_login_info(self, info_type):
        return_value = self.dynamicCall("GetLoginInfo(QString)", info_type)
        if info_type == "ACCLIST":
            return_value = return_value.split(';')
        elif info_type == "ACCNO":
            return_value = return_value.split(';')[:-1]

        print(info_type, ": ", return_value)
        return return_value

    def get_code_list_by_market(self, market_type):
        code_list = self.dynamicCall("GetCodeListByMarket(QString)", market_type)
        code_list = code_list.split(';')[:-1]
        return code_list

    def get_master_code_name(self, code):
        code_name = self.dynamicCall("GetMasterCodeName(QString", code)
        return code_name

 

종목정보 관련 함수

함수 명 함수 설명
BSTR GetCodeListByMarket(BSTR sMarket) GetCodeListByMarket(
  BSTR sMarket    // 시장구분값
)

주식 시장별 종목코드 리스트를 ';'로 구분해서 전달합니다.
시장구분값을 ""공백으로하면 전체시장 코드리스트를 전달합니다.

로그인 한 후에 사용할 수 있는 함수입니다.

[시장구분값]
0 : 코스피
10 : 코스닥
3 : ELW
8 : ETF
50 : KONEX
4 :  뮤추얼펀드
5 : 신주인수권
6 : 리츠
9 : 하이얼펀드
30 : K-OTC
BSTR GetMasterCodeName(BSTR strCode) GetMasterCodeName(
  BSTR strCode    // 종목코드
)
종목코드에 해당하는 종목명을 전달합니다.
로그인 한 후에 사용할 수 있는 함수입니다.
LONG GetMasterListedStockCnt(BSTR strCode) GetMasterListedStockCnt(
  BSTR strCode  // 종목코드
)
입력한 종목코드에 해당하는 종목 상장주식수를 전달합니다.
로그인 한 후에 사용할 수 있는 함수입니다.
          
BSTR GetMasterConstruction(BSTR strCode) GetMasterConstruction(
  BSTR strCode  // 종목코드
)
입력한 종목코드에 해당하는 종목의 감리구분을 전달합니다.
(정상, 투자주의, 투자경고, 투자위험, 투자주의환기종목)
로그인 한 후에 사용할 수 있는 함수입니다.          
BSTR GetMasterListedStockDate(BSTR strCode) GetMasterListedStockDate(
  BSTR strCode    // 종목코드
)
입력한 종목의 상장일을 전달합니다.
로그인 한 후에 사용할 수 있는 함수입니다.
BSTR GetMasterLastPrice(BSTR strCode) GetMasterLastPrice(
  BSTR strCode    // 종목코드
)
입력한 종목의 당일 기준가를 전달합니다.
로그인 한 후에 사용할 수 있는 함수입니다.
BSTR GetMasterStockState(BSTR strCode) GetMasterStockState(
  BSTR strCode  // 종목코드
)
입력한 종목의 증거금 비율, 거래정지, 관리종목, 감리종목, 투자융의종목, 담보대출, 액면분할, 신용가능 여부를 전달합니다.
로그인 한 후에 사용할 수 있는 함수입니다.
BSTR GetBranchCodeName() 특정TR 조회에 필요한 회원사 정보를 회원사 코드와 회원사 이름으로 구성해서 전달합니다.
각 회원사 정보는 구분자 ';'로 분리되어 있으며 한 회원사 정보에는 구분자 '|'로 회원사 코드와 회원사 이름을 분리합니다.
전체적인 회원사 구성과 함수에서 전달받은 회원사 정보는 다음과 같습니다.

"회원사코드0|회원사이름0;회원사코드1|회원사이름1;...회원사코드n|회원사이름n;"
  예) 001|교  보;002|신한금융투자;003|한국투자증권;...;827|모아증권중개;829|동양오리온

로그인 한 후에 사용할 수 있는 함수입니다.
BSTR GetFutureList() 지수선물 종목코드 리스트를 ';'로 구분해서 전달합니다.
로그인 한 후에 사용할 수 있는 함수입니다.
BSTR GetActPriceList() 지수옵션 행사가에 100을 곱해서 소수점이 없는 값을 ';'로 구분해서 전달합니다.

로그인 한 후에 사용할 수 있는 함수입니다.
-------------------------------------------------------------------
[지수옵션 행사가 사용예시]
CString strActPriceList(OpenAPI.GetActPriceList());
"19000;19250;19500;19750;20000;20250;20500;20750;21000;21250;21500;21750;..."
-------------------------------------------------------------------
BSTR GetMonthList() 지수옵션 월물정보를 ';'로 구분해서 전달하는데 순서는 콜 11월물 ~ 콜 최근월물 풋 최근월물 ~ 풋 최근월물가 됩니다.
로그인 한 후에 사용할 수 있는 함수입니다.

-------------------------------------------------------------------
[지수옵션 월물조회 사용예시]
CString strMonthList(OpenAPI.GetMonthList());
"201812;201806;201712;201706;201703;201612;201611;201610;201609;201608;201607;..."
-------------------------------------------------------------------
BSTR GetOptionCode(BSTR strActPrice, int nCp, BSTR strMonth) GetOptionCode(
  BSTR strActPrice,   // 소수점을 포함한 행사가
  int nCp,    // 콜풋구분값, 콜:2, 풋:3
  BSTR strMonth   // 6자리 월물
)
인자로 지정한 지수옵션 코드를 전달합니다.
로그인 한 후에 사용할 수 있는 함수입니다.
-------------------------------------------------------------------[지수옵션 코드 사용예시]
CString strOptCode = OpenAPI.GetOptionCode(_T("247.50"), 2, _T("201607"));
-------------------------------------------------------------------
BSTR GetOptionATM() 지수옵션 소수점을 제거한 ATM값을 전달합니다.
예를들어 ATM값이 247.50 인 경우 24750이 전달됩니다.
로그인 한 후에 사용할 수 있는 함수입니다.
BSTR GetFutureList(LPCTSTR strBaseAssetGb) GetSFutureList(
  BSTR strBaseAssetGb,   // 기초자산 구분값
)
기초자산 구분값을 인자로 받아서 주식선물 종목코드, 종목명, 기초자산이름을 구할수 있습니다.
입력값을 공백으로 하면 주식선물 전체 종목코드를 얻을 수 있습니다.
전달되는 데이터 형식은 다음과 같습니다.
"종목코드1^종목명1^기초자산이름1;종목코드2^종목명2^기초자산이름2;...;종목코드n^종목명n^기초자산이름n;"

로그인 한 후에 사용할 수 있는 함수입니다.