1. 국내주식/1-3. 키움 OpenAPI (기타)

(주식 자동 매매) 키움증권 OpenAPI - 거래명세원 받기(opt10002)

봄이오네 2022. 10. 17. 08:06
반응형

1. 들어가며

단타를 하는 일부 주식 고수들은 시간대 별로 기관/외인의 거래량을 본다고 한다.
키움에서 거래원(거래량이 많은 기관/외인)을 보는 화면 번호는 0129이다.

아래의 거래원을 구현할 수 있는 코드를 구현해 보고자 한다. ('22.9.30 기준)

< 그림1. 삼성전자의 매수/매도 거래원 상위 5개 현황 ('22.9.30) >


2. 사전 준비

KOA StudioSA에 로그인하면,
아래와 같이 TR요청 목록에서 정보를 얻을 수 있다.

KOA StudioSA의 TR목록 탭을 선택
opt10002에서는 input은 1가지(종목코드)를 ④에 입력
사용할 함수 2개 : SetInputValue 함수(서버에 입력), CommRqData 함수(서버에 요청)
④ 종목코드 입력
⑤ 종목코드, 종목명, 주요 거래원 등을 출력

TR요청의 파이썬 코드 만드는 방법
1) SetInputValue 함수로 자료를 키움서버에 입력
2) CommRqData 함수로 자료를 키움서버에 요청
3) OnReceiveTrData 함수로 CommRqData으로 요청한 데이터를
trdata_get 를 연결하여 결과값 전달(수신)
4) trdata_get 함수로 자료 수신

< 그림2. KOA Studio에서 조회한 opt10002 화면 >


3. 코드 설명


※ 로그인 함수는 아래에서 설명한다.
https://springcoming.tistory.com/17?category=1048804

 

(주식 자동 매매) 키움증권 OpenAPI 로그인

1. 들어가며 키움증권에서 제공하는 OpenAPI를 통해 키움서버에 접근하기 위해서는, 파이썬을 통해 OpenAPI에 접속하여 로그인할 수 있어야 한다. 당초 로그인 후 예수금 받기까지 진행하려고 했으

springcoming.tistory.com

 

< 그림3. 로그인 및 TR 자료를 요청하는 화면 >


1줄~23줄 : 로그인 관련이며, 위에서 설명하였으므로 생략
25줄 : TR 요청을 위해 rq_data_opt10002 함수를 만들어 준다.
27줄 : 81줄에서 입력한 삼성전자(005930)의 코드가 들어가는 자리는
27줄의"stock_code_name"이며 SetInputValue에 의해 키움서버에 입력된다.
28줄 : 입력된 종목코드를 CommRqData 함수를 통해 키움서버로 opt10002 데이터를 요청한다.

< 그림 4. 키움서버에서 수신받은 자료를 변수에 담는 화면 >


32줄 : trdata_get 함수를 선언하여, 28줄의 CommRqData함수로 요청한 데이터를 수신한다.
* 28줄(CommRqData, 요청)와 32줄(trdata_get, 수신)을 연결하는 것
11줄(self.kiwoom.OnReceiveTrData.connect(self.trdata_get)) 함수이다.
33줄 : 요청한 rqname가 'opt_10002'이면,
35줄 : 코드번호를 stock_code_num 변수에 담아라
37줄~57줄 : 거래가 가장 많은 매수거래원명1(37줄)부터~매도거래량5(57줄)까지,
35줄과 동일한 패턴으로 자료를 수신받는다.

< 그림5. 수신받은 데이터를 화면에 출력 >


59줄 : 수신받은 코드번호(stock_code_num), 매도가 가장 많았던 매도거래원명1, 그 매도량을 출력한다.
60줄 ~ 69줄 : 59줄과 동일하다.
81줄 : 25줄의 rq_data_opt10002 함수에 삼성전자(005930)을 넣고, 실행하라

데이터를 출력(print)한 화면은 아래와 같다.

< 그림6. 수신받은 데이터의 결과 >


4. 전체 코드

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

class btl_system():
    def __init__(self):
        self.kiwoom = QAxWidget("KHOPENAPI.KHOpenAPICtrl.1")

        self.kiwoom.OnEventConnect.connect(self.login_Connect)
        self.kiwoom.OnReceiveTrData.connect(self.trdata_get)

        print("로그인 요청!")
        self.kiwoom.dynamicCall("CommConnect()")
        self.login_event_loop = QEventLoop()
        self.login_event_loop.exec_()

    def login_Connect(self, nErrCode):
        if nErrCode == 0:
            print('로그인 성공하였습니다!')
        else:
            print('로그인 실패하였습니다!')
        self.login_event_loop.exit()

    def rq_data_opt10002(self, stock_code_name):
        print("81줄에서 입력받은 종목코드를 키움서버에 요청합니다.""\n")
        self.kiwoom.dynamicCall("SetInputValue(QString, QString)", "종목코드", stock_code_name)
        self.kiwoom.dynamicCall("CommRqData(QString, QString, int, QString)", "opt_10002", "opt10002", 0, "1002")
        self.tr_event_loop = QEventLoop()
        self.tr_event_loop.exec_()

    def trdata_get(self, sScrNo, rqname, strcode, sRecordName, sPreNext, nDataLength, sErrorCode, sMessage, sSplmMsg):
        if rqname == 'opt_10002':

            stock_code_num = self.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", "opt10002", "주식거래원요청", 0, "종목코드").strip()

            buy_name1 = self.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", "opt10002", "주식거래원요청", 0, "매수거래원명1").strip()
            buy_name2 = self.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", "opt10002", "주식거래원요청", 0, "매수거래원명2").strip()
            buy_name3 = self.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", "opt10002", "주식거래원요청", 0, "매수거래원명3").strip()
            buy_name4 = self.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", "opt10002", "주식거래원요청", 0, "매수거래원명4").strip()
            buy_name5 = self.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", "opt10002", "주식거래원요청", 0, "매수거래원명5").strip()
            buy_name_qty1 = int(self.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", "opt10002", "주식거래원요청", 0, "매수거래량1"))
            buy_name_qty2 = int(self.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", "opt10002", "주식거래원요청", 0, "매수거래량2"))
            buy_name_qty3 = int(self.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", "opt10002", "주식거래원요청", 0, "매수거래량3"))
            buy_name_qty4 = int(self.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", "opt10002", "주식거래원요청", 0, "매수거래량4"))
            buy_name_qty5 = int(self.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", "opt10002", "주식거래원요청", 0, "매수거래량5"))

            sell_name1 = self.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", "opt10002", "주식거래원요청", 0, "매도거래원명1").strip()
            sell_name2 = self.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", "opt10002", "주식거래원요청", 0, "매도거래원명2").strip()
            sell_name3 = self.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", "opt10002", "주식거래원요청", 0, "매도거래원명3").strip()
            sell_name4 = self.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", "opt10002", "주식거래원요청", 0, "매도거래원명4").strip()
            sell_name5 = self.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", "opt10002", "주식거래원요청", 0, "매도거래원명5").strip()
            sell_name_qty1 = abs(int(self.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", "opt10002", "주식거래원요청", 0, "매도거래량1")))
            sell_name_qty2 = abs(int(self.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", "opt10002", "주식거래원요청", 0, "매도거래량2")))
            sell_name_qty3 = abs(int(self.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", "opt10002", "주식거래원요청", 0, "매도거래량3")))
            sell_name_qty4 = abs(int(self.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", "opt10002", "주식거래원요청", 0, "매도거래량4")))
            sell_name_qty5 = abs(int(self.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", "opt10002", "주식거래원요청", 0, "매도거래량5")))

            print("코드번호 %s의 매도거래원명1은 %s이며, 그 매도량1은 %d이다." %(stock_code_num, sell_name1, sell_name_qty1))
            print("코드번호 %s의 매도거래원명2은 %s이며, 그 매도량2은 %d이다." %(stock_code_num, sell_name2, sell_name_qty2))
            print("코드번호 %s의 매도거래원명3은 %s이며, 그 매도량3은 %d이다." %(stock_code_num, sell_name3, sell_name_qty3))
            print("코드번호 %s의 매도거래원명4은 %s이며, 그 매도량4은 %d이다." %(stock_code_num, sell_name4, sell_name_qty4))
            print("코드번호 %s의 매도거래원명5은 %s이며, 그 매도량5은 %d이다." %(stock_code_num, sell_name5, sell_name_qty5))

            print("\n""코드번호 %s의 매수거래원명1은 %s이며, 그 매수량1은 %d이다." %(stock_code_num, buy_name1, buy_name_qty1))
            print("코드번호 %s의 매수거래원명2은 %s이며, 그 매수량2은 %d이다." %(stock_code_num, buy_name2, buy_name_qty2))
            print("코드번호 %s의 매수거래원명3은 %s이며, 그 매수량3은 %d이다." %(stock_code_num, buy_name3, buy_name_qty3))
            print("코드번호 %s의 매수거래원명4은 %s이며, 그 매수량4은 %d이다." %(stock_code_num, buy_name4, buy_name_qty4))
            print("코드번호 %s의 매수거래원명5은 %s이며, 그 매수량5은 %d이다." %(stock_code_num, buy_name5, buy_name_qty5))


        try:
            self.tr_event_loop.exit()
        except AttributeError:
            pass

if __name__ == "__main__":
    app = QApplication(sys.argv)
    btl = btl_system()

    btl.rq_data_opt10002("005930")

    app.exec_()

5. 마치며

거래명세원이라는 단어가 약간은 생소하다.
매수/매도를 많이 한 상위 5개 기관으로 바꾸면 안될까?
거래원이라는 개념을 써야하는지 약간의 의문이 들긴 하다. ^^

그림1에서 인상깊은 것은 외국계 기업이 삼성전자를 1.7백만 주를 샀다는 것이다.
모건스탠리와 메릴린치는 단타를 많이 하는 경향이 있다고들 한다.
매수를 그만큼 했다는 소리는 언제 다시 매도폭탄이 떨어질지 모르니,
투자에 유의를 기울이길 바란다.

거래명세원(opt10002)를 통해 사용자는
주식을 많이 산 기관/외국 기관 현황을 알 수 있다는 내용의 설명이었다.

반응형