1. 들어가며
지난 번에는 4종목의 현재가를 pandas모듈의 데이터프레임에 담아 출력해 보았다.
이번에는 4종목의 현재가를 변수에 담아 향후 거래할 때,
현재가 > 매수가이면, 칼같이 매도하는 코드를 알아보자
- 아래 예시의 익절/손절을 구하기 위해서는 매수가격도 구현해야 한다.ㅠㅠ
* 4종목 : 삼성전자(005930), 경동나비엔(009450), 아프리카TV(067160), 토니모리(214420)
- (익절) 현재가격 > 매수가격+ 2,000원이면, 시장가격으로 매도 예정
- (손절) 현재가격 < 매수가격 - 3,000원이면, 시장가격으로 매도 예정
2. 사전 준비
KOA StudioSA에서 받아오는 정보는 아래와 같다.
(KOA StudioSA 관련 내용은 아래에서 확인 가능한 점을 고려하여, 여기서는 생략한다.)
https://springcoming.tistory.com/24?category=1048804
3. 코드 구현
- 키움증권의 OpenAPI에 로그인하고,
- 관심종목(interesting_lists)에 4개 종목코드를 문자형으로 넣어준다.
- 현재가격은 향후 익절/손절을 위해 자주 쓰이는 변수이므로, 전역변수로 선언한다.
※ 앞에서 설명한 코드는 생략한다.
5줄 : 위의 코드에서는 DataFrame를 활용하지 않으므로,
pandas를 임포트하였으나, 활성화 되지 아니한다. (5줄은 생략해도 된다)
13줄 : 키움서버로부터 받아온 데이터를 trdata_get함수에 넣기위해,
키움OpenAPI에서 제공하는 OnReceiveTrData와 연결
21줄 : 관심종목(interesting_lists)를 프로그램의 여러곳에서 사용할 것이므로, 전역변수(global) 선언
22줄 : 관심종목(interesting_lists)를 관리하고자 하는 종목을 넣어준다.
문자형(쌍 따옴표)으로 넣어주어야 한다.
31줄 : 80줄의 명령어 수행을 위해, 임의로 rq_data_opt10001함수를 선언한다.
* 80줄 : 79줄의 for문을 통한 interesting_lists의 종목코드를 뽑아서
31줄의 rq_data_opt10001함수로 순차적으로 전달하는 것
33줄 : dynamicCall 함수로 SetInputValue 함수를 통해 종목코드를 키움서버에 입력
* dynamicCall 함수 : PyQt5에서 제공하며, 키움 서버에 데이터를 요청할 때 사용
34줄 : dynamicCall 함수로 CommRqData 함수를 통해 종목코드를 키움서버에 요청
35줄 : 데이터 입력/요청이 끝날때까지, QEventLoop()를 선언
36줄 : tr_event_loop를 실행 (데이터 입력/요청 완료될 때까지 루프를 돌며 대기함)
38줄 : SetInputValue(입력), CommRqData(요청)으로 받아온 데이터를 수신/저장하기 위한 함수 선언
40줄~41줄 : 종목코드와 현재가를 각각 받아온다.
43줄~44줄 : 종목코드는 앞뒤의 0000 혹은 빈칸을 없애고,
현재가는 바로 전의 가격보다 작으면 음수(-)가 나오므로, 양수로 변환(abs)
49줄~67줄 : 22줄에서 리시트형으로 선언된 관심종목(interesting_lists)에 대해
리스트 내 항목을 하나씩 뽑아오는 것이 핵심이다.
* 22줄 : interesting_lists = ["005930", "009450", "067160", "214420"]
* interesting_lists[0]이면 "005930"을 말한다.
49줄 : 40줄~41줄에서 받아온 종목코드가 005930이면,
51줄 : il_current_price0 변수에 넣어라.
54줄 : 40줄~41줄에서 받아온 종목코드가 009450이면
56줄 : il_current_price1 변수에 넣어라.
59줄 : 40줄~41줄에서 받아온 종목코드가 067160이면
61줄 : il_current_price2 변수에 넣어라.
64줄 : 40줄~41줄에서 받아온 종목코드가 214420이면
66줄 : il_current_price3 변수에 넣어라.
78줄 : 데이터를 지속적/반복적으로 받기 위해 current_price24 함수 선언
79줄 : 22줄의 interesting_lists의 종목코드를 순차적으로 for문을 돌려줌
80줄 : 클래스내의 rq_data_opt10001을 실행
→ 31줄의 stock_code에 종목코드가 순차적으로 들어간다.
81줄 : threading.Timer을 통해 10초마다 반복적으로 실행
(위의 코드에서는 반복적으로 현재가를 받아온다)
83줄 : current_price24() 함수 실행을 통해
81줄의 threading.Timer 함수를 최초로 시작하는 함수
4. 전체 코드
import sys
from PyQt5.QAxContainer import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import pandas as pd
import threading
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_()
global interesting_lists
interesting_lists = ["005930", "009450", "067160", "214420"]
def login_Connect(self, nErrCode):
if nErrCode == 0:
print('로그인 성공했습니다!')
else:
print('로그인 실패했습니다!')
self.login_event_loop.exit()
def rq_data_opt10001(self, stock_code):
print("22줄에서 입력받은 종목코드를 키움서버에 요청합니다.")
self.kiwoom.dynamicCall("SetInputValue(QString, QString)", "종목코드", stock_code)
self.kiwoom.dynamicCall("CommRqData(QString, QString, int, QString)", "opt_10001", "opt10001", 0, "0303")
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_10001":
stock_code = self.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", "opt10001", "주식기본정보요청", 0, "종목코드")
current_price1 = self.kiwoom.dynamicCall("GetCommData(QString, QString, int, QString)", "opt10001", "주식기본정보요청", 0, "현재가")
stock_code = stock_code.strip()
current_price1 = abs(int(current_price1))
# print(stock_code) # 결과값 출력하는 곳
# print(current_price1) # 결과값 출력하는 곳
if stock_code == interesting_lists[0]:
global il_current_price0 # il = interesting_list (22줄의 관심리스트)
il_current_price0 = current_price1
print("종목코드 {}의 현재가는 {}원이다.".format(interesting_lists[0], il_current_price0))
elif stock_code == interesting_lists[1]:
global il_current_price1
il_current_price1 = current_price1
print("종목코드 {}의 현재가는 {}원이다.".format(interesting_lists[1], il_current_price1))
elif stock_code == interesting_lists[2]:
global il_current_price2
il_current_price2 = current_price1
print("종목코드 {}의 현재가는 {}원이다.".format(interesting_lists[2], il_current_price2))
else:
global il_current_price3
il_current_price3 = current_price1
print("종목코드 {}의 현재가는 {}원이다.".format(interesting_lists[3], il_current_price3))
try:
self.tr_event_loop.exit()
except AttributeError:
pass
if __name__ == "__main__":
app = QApplication(sys.argv)
btl = btl_system()
def current_price24():
for interesting_list in interesting_lists:
btl.rq_data_opt10001(interesting_list)
threading.Timer(10, current_price24).start()
current_price24()
app.exec_()
5. 마치며
4종목의 현재가를 받아오는 것은,
향후 익절/손절을 위한 판단을 위해 절대적으로 필요한 내용이다.
물론 코드가 길어진 측면이 없지 않아 있지만,
전역변수를 선언하여 프로그램의 어디에서도 활용할 수 있다.
필요할 때마다 현재가를 업데이트하여,
뇌동매매가 아닌 익절/손절 라인이 오면 칼같이 매도하도록 해야 한다.
이번에는 10초마다 반복하는 것으로 했지만,
향후에는 특정종목을 매수했을때만 실행될 수 있도록
코드를 구현해 보고 싶다.
'1. 국내주식 > 1-2. 키움 OpenAPI (사용)' 카테고리의 다른 글
(주식 자동 매매) 키움증권 OpenAPI - 미체결 주문을 SendOrder 함수로 취소하기 (1) 취소 방법 (0) | 2022.10.06 |
---|---|
(주식 자동 매매) 키움증권 OpenAPI - 1분봉 데이터 실시간 받기(opt10080) (2) | 2022.10.05 |
(주식 자동 매매) 키움증권 OpenAPI - SendOrder함수를 이용하여 매수/매도하기 (0) | 2022.10.01 |
(주식 자동 매매) 키움증권 OpenAPI 매수한 4종목의 매수가격, 매수량 받아오기(opt10085) (0) | 2022.09.28 |
(주식 자동 매매) 키움증권 OpenAPI 4종목 현재가 조회(opt10001) (0) | 2022.09.26 |
(주식 자동 매매) 키움증권 OpenAPI 현재가 조회(opt10001) (0) | 2022.09.25 |
(주식 자동 매매) 키움증권 OpenAPI 예수금/주문가능금액 조회 (opw00001) (0) | 2022.09.22 |
(주식 자동 매매) 키움증권 OpenAPI 로그인 (0) | 2022.09.21 |