Skip to content

Commit

Permalink
0131_해외주식 실시간호가_미국/아시아 TR 분리
Browse files Browse the repository at this point in the history
- 수정한 코드(2) : ws_domestic_overseas_all.py, ws_overseas_stock.py
. 해외주식 실시간호가 TR 미국/아시아 분리수정
  - 미국 : HDFSASP0
  - 아시아 : HDFSASP1
  • Loading branch information
koreainvestment committed Jan 31, 2023
1 parent fae02e1 commit dbe63dd
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 118 deletions.
19 changes: 14 additions & 5 deletions websocket/python/ws_domestic_overseas_all.py
Original file line number Diff line number Diff line change
Expand Up @@ -398,8 +398,11 @@ async def connect():
### 1. 국내주식 호가, 체결가, 체결통보 ###
# code_list = [['1','H0STASP0','005930'],['1','H0STCNT0','005930'],['1','H0STCNI0','HTS ID를 입력하세요']]

### 2. 해외주식(미국) 호가, 체결가, 체결통보 ###
# code_list = [['1','HDFSASP1','DNASAAPL'],['1','HDFSCNT0','DNASAAPL'],['1','H0GSCNI0','HTS ID를 입력하세요']]
### 2-1. 해외주식(미국) 호가, 체결가, 체결통보 ###
# code_list = [['1','HDFSASP0','DNASAAPL'],['1','HDFSCNT0','DNASAAPL'],['1','H0GSCNI0','HTS ID를 입력하세요']]

### 2-2.해외주식(아시아) 호가, 체결가, 체결통보 ###
# code_list = [['1','HDFSASP1','DHKS00003'],['1','HDFSCNT0','DHKS00003'],['1','H0GSCNI0','HTS ID를 입력하세요']]

### 3. 국내선물옵션 호가, 체결가, 체결통보 ###
# code_list = [['1','H0IFASP0','101S12'],['1','H0IFCNT0','101S12'], # 선물호가, 체결가
Expand All @@ -411,9 +414,10 @@ async def connect():
# ['1','HDFFF020','OESH23 C3900'],['1','HDFFF010','OESH23 C3900'], # 해외옵션 체결가, 호가
# ['1','HDFFF2C0','HTS ID를 입력하세요']] # 해외선물옵션 체결통보

### 1+2+3+4. 국내주식, 해외주식(미국), 국내선물옵션, 해외선물옵션 호가, 체결가, 체결통보 ###
### 1+2+3+4. 국내주식, 해외주식(미국), 해외주식(아시아), 국내선물옵션, 해외선물옵션 호가, 체결가, 체결통보 ###
code_list = [['1','H0STASP0','005930'],['1','H0STCNT0','005930'],['1','H0STCNI0','HTS ID를 입력하세요'],
['1','HDFSASP1','DNASAAPL'],['1','HDFSCNT0','DNASAAPL'],['1','H0GSCNI0','HTS ID를 입력하세요'],
['1','HDFSASP0','DNASAAPL'],['1','HDFSCNT0','DNASAAPL'],['1','H0GSCNI0','HTS ID를 입력하세요'],
['1','HDFSASP1','DHKS00003'],['1','HDFSCNT0','DHKS00003'],['1','H0GSCNI0','HTS ID를 입력하세요'],
['1','H0IFASP0','101S12'],['1','H0IFCNT0','101S12'],['1','H0IOASP0','201S12315'],['1','H0IOCNT0','201S12322'], ['1','H0IFCNI0','HTS ID를 입력하세요'],
['1','HDFFF020','FCAZ22'],['1','HDFFF010','FCAZ22'],['1','HDFFF020','OESH23 C3900'],['1','HDFFF010','OESH23 C3900'],['1','HDFFF2C0','HTS ID를 입력하세요']]

Expand Down Expand Up @@ -454,8 +458,13 @@ async def connect():
data_cnt = int(recvstr[2]) # 체결데이터 개수
stockspurchase_domestic(data_cnt, recvstr[3])

elif trid0 == "HDFSASP0": # 해외주식호가tr 일경우의 처리 단계
print("#### 해외(미국)주식호가 ####")
stockhoka_overseas(recvstr[3])
time.sleep(1)

elif trid0 == "HDFSASP1": # 해외주식호가tr 일경우의 처리 단계
print("#### 해외주식호가 ####")
print("#### 해외(아시아)주식호가 ####")
stockhoka_overseas(recvstr[3])
time.sleep(1)

Expand Down
209 changes: 96 additions & 113 deletions websocket/python/ws_overseas_stock.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# 웹 소켓 모듈을 선언한다.
# -*- coding: utf-8 -*-
### 모듈 임포트 ###
import websockets
import json
import requests
Expand All @@ -15,6 +16,8 @@
key_bytes = 32


### 함수 정의 ###

# AES256 DECODE
def aes_cbc_base64_dec(key, iv, cipher_text):
"""
Expand All @@ -29,7 +32,6 @@ def aes_cbc_base64_dec(key, iv, cipher_text):

# 웹소켓 접속키 발급
def get_approval(key, secret):

# url = https://openapivts.koreainvestment.com:29443' # 모의투자계좌
url = 'https://openapi.koreainvestment.com:9443' # 실전투자계좌
headers = {"content-type": "application/json"}
Expand All @@ -43,8 +45,10 @@ def get_approval(key, secret):
return approval_key


# 해외주식체결 출력라이브러리
def stockhoka(data):
### 2. 해외주식 ###

# 해외주식호가 출력라이브러리
def stockhoka_overseas(data):
""" 넘겨받는데이터가 정상인지 확인
print("stockhoka[%s]"%(data))
"""
Expand All @@ -68,7 +72,7 @@ def stockhoka(data):


# 해외주식체결처리 출력라이브러리
def stockspurchase(data_cnt, data):
def stockspurchase_overseas(data_cnt, data):
print("============================================")
menulist = "실시간종목코드|종목코드|수수점자리수|현지영업일자|현지일자|현지시간|한국일자|한국시간|시가|고가|저가|현재가|대비구분|전일대비|등락율|매수호가|매도호가|매수잔량|매도잔량|체결량|거래량|거래대금|매도체결량|매수체결량|체결강도|시장구분"
menustr = menulist.split('|')
Expand All @@ -82,7 +86,7 @@ def stockspurchase(data_cnt, data):


# 해외주식체결통보 출력라이브러리
def stocksigningnotice(data, key, iv):
def stocksigningnotice_overseas(data, key, iv):
menulist = "고객 ID|계좌번호|주문번호|원주문번호|매도매수구분|정정구분|주문종류2|단축종목코드|주문수량|체결단가|체결시간|거부여부|체결여부|접수여부|지점번호|체결수량|계좌명|체결종목명|해외종목구분|담보유형코드|담보대출일자"
menustr1 = menulist.split('|')

Expand All @@ -102,129 +106,108 @@ def stocksigningnotice(data, key, iv):


async def connect():
# 웹 소켓에 접속.( 주석은 koreainvest test server for websocket)
## 시세데이터를 받기위한 데이터를 미리 할당해서 사용한다.

g_appkey = '앱키를 입력하세요'
g_appsceret = '앱 시크릿키를 입력하세요'
g_approval_key = get_approval(g_appkey, g_appsceret)
print("approval_key [%s]" % (g_approval_key))

stockcode = '종목코드입력하세요' # D+시장구분(3자리)+종목코드
# 예) DNASAAPL : D+NAS(나스닥)+AAPL(애플)
htsid = 'HTS ID를 입력하세요' # 체결통보용 htsid 입력
custtype = 'P' # customer type, 개인:'P' 법인 'B'
url = 'ws://ops.koreainvestment.com:21000'
# url = 'ws://ops.koreainvestment.com:31000' # 모의투자계좌
url = 'ws://ops.koreainvestment.com:21000' # 실전투자계좌

g_approval_key = get_approval(g_appkey, g_appsceret)
print("approval_key [%s]" % (g_approval_key))
# 원하는 호출을 [tr_type, tr_id, tr_key] 순서대로 리스트 만들기

### 해외주식(미국) 호가, 체결가, 체결통보 ###
# code_list = [['1','HDFSASP0','DNASAAPL'],['1','HDFSCNT0','DNASAAPL'],['1','H0GSCNI0','HTS ID를 입력하세요']]

### 해외주식(아시아) 호가, 체결가, 체결통보 ###
# code_list = [['1','HDFSASP1','DHKS00003'],['1','HDFSCNT0','DHKS00003'],['1','H0GSCNI0','HTS ID를 입력하세요']]

### 해외주식(미국) 호가, 체결가, 체결통보, 해외주식(아시아) 호가, 체결가, 체결통보 ###
code_list = [['1','HDFSASP0','DNASAAPL'],['1','HDFSCNT0','DNASAAPL'],['1','H0GSCNI0','HTS ID를 입력하세요'],
['1','HDFSASP1','DHKS00003'],['1','HDFSCNT0','DHKS00003'],['1','H0GSCNI0','HTS ID를 입력하세요']]

senddata_list=[]

async with websockets.connect(url, ping_interval=None) as websocket:

"""" 주석처리는 더블쿼트 3개로 처리
"""
while True:
print("1.해외주식호가, 2.해외주식호가해제, 3.해외주식체결, 4.해외주식체결해제, 5.해외주식체결통보(고객), 6.해외주식체결통보해제(고객), 7.해외주식체결통보(모의), 8.해외주식체결통보해제(모의)")
print("Input Command :")
cmd = input()

# 입력값 체크 step
if cmd < '0' or cmd > '9':
print("> Wrong Input Data", cmd)
continue
elif cmd == '0':
print("Exit!!")
break

# 입력값에 따라 전송 데이터셋 구분 처리
if cmd == '1': # 해외주식호가 등록
tr_id = 'HDFSASP1'
tr_type = '1'
elif cmd == '2': # 해외주식호가 등록해제
tr_id = 'HDFSASP1'
tr_type = '2'
elif cmd == '3': # 해외주식체결 등록
tr_id = 'HDFSCNT0'
tr_type = '1'
elif cmd == '4': # 해외주식체결 등록해제
tr_id = 'HDFSCNT0'
tr_type = '2'
elif cmd == '5': # 해외주식체결통보 등록(고객용)
tr_id = 'H0GSCNI0' # 고객체결통보
tr_type = '1'
elif cmd == '6': # 해외주식체결통보 등록해제(고객용)
tr_id = 'H0GSCNI0' # 고객체결통보
tr_type = '2'
elif cmd == '7': # 해외주식체결통보 등록(모의)
tr_id = 'H0GSCNI9' # 테스트용 직원체결통보
tr_type = '1'
elif cmd == '8': # 해외주식체결통보 등록해제(모의)
tr_id = 'H0GSCNI9' # 테스트용 직원체결통보
tr_type = '2'
else:
senddata = 'wrong inert data'

# send json, 체결통보는 tr_key 입력항목이 상이하므로 분리를 한다.
if cmd == '5' or cmd == '6' or cmd == '7' or cmd == '8':
senddata = '{"header":{"approval_key":"' + g_approval_key + '","custtype":"' + custtype + '","tr_type":"' + tr_type + '","content-type":"utf-8"},"body":{"input":{"tr_id":"' + tr_id + '","tr_key":"' + htsid + '"}}}'
else:
senddata = '{"header":{"approval_key":"' + g_approval_key + '","custtype":"' + custtype + '","tr_type":"' + tr_type + '","content-type":"utf-8"},"body":{"input":{"tr_id":"' + tr_id + '","tr_key":"' + stockcode + '"}}}'

print('Input Command is :', senddata)

await websocket.send(senddata)
time.sleep(1)

# 데이터가 오기만 기다린다.
for i,j,k in code_list:
temp = '{"header":{"approval_key": "%s","custtype":"P","tr_type":"%s","content-type":"utf-8"},"body":{"input":{"tr_id":"%s","tr_key":"%s"}}}'%(g_approval_key,i,j,k)
senddata_list.append(temp)

while True:

async with websockets.connect(url, ping_interval=30) as websocket:

for senddata in senddata_list:
await websocket.send(senddata)
time.sleep(0.5)
print(f"Input Command is :{senddata}")

while True:
data = await websocket.recv()
print("Recev Command is :", data)
if data[0] == '0' or data[0] == '1': # 실시간 데이터일 경우
trid = jsonObject["header"]["tr_id"]

try:

data = await websocket.recv()
time.sleep(0.5)
# print(f"Recev Command is :{data}") # 정제되지 않은 Request / Response 출력

if data[0] == '0':
recvstr = data.split('|') # 수신데이터가 실데이터 이전은 '|'로 나뉘어져있어 split
trid0 = recvstr[1]
if trid0 == "HDFSASP1": # 해외주식호가tr 일경우의 처리 단계
print("#### 해외주식호가 ####")
stockhoka(recvstr[3])

if trid0 == "HDFSASP0": # 해외주식호가tr 일경우의 처리 단계
print("#### 해외(미국)주식호가 ####")
stockhoka_overseas(recvstr[3])
time.sleep(1)

elif trid0 == "HDFSCNT0": # 주식체결 데이터 처리

elif trid0 == "HDFSASP1": # 해외주식호가tr 일경우의 처리 단계
print("#### 해외(아시아)주식호가 ####")
stockhoka_overseas(recvstr[3])
time.sleep(1)

elif trid0 == "HDFSCNT0": # 해외주식체결 데이터 처리
print("#### 해외주식체결 ####")
data_cnt = int(recvstr[2]) # 체결데이터 개수
stockspurchase(data_cnt, recvstr[3])
data_cnt = int(recvstr[2]) # 해외체결데이터 개수
stockspurchase_overseas(data_cnt, recvstr[3])

elif data[0] == '1':

recvstr = data.split('|') # 수신데이터가 실데이터 이전은 '|'로 나뉘어져있어 split
trid0 = recvstr[1]
if trid0 == "H0GSCNI0" or trid0 == "H0GSCNI9" or trid0 == "H0GSCNI0" or trid0 == "H0GSCNI9": # 해외주실체결 통보 처리
stocksigningnotice(recvstr[3], aes_key, aes_iv)
await websocket.send(senddata)

# clearConsole()
# break;
else:
jsonObject = json.loads(data)
trid = jsonObject["header"]["tr_id"]

if trid != "PINGPONG":
rt_cd = jsonObject["body"]["rt_cd"]
if rt_cd == '1': # 에러일 경우 처리
print("### ERROR RETURN CODE [ %s ][ %s ] MSG [ %s ]" % (jsonObject["header"]["tr_key"], rt_cd, jsonObject["body"]["msg1"]))
#break
elif rt_cd == '0': # 정상일 경우 처리
print("### RETURN CODE [ %s ][ %s ] MSG [ %s ]" % (jsonObject["header"]["tr_key"], rt_cd, jsonObject["body"]["msg1"]))
# 체결통보 처리를 위한 AES256 KEY, IV 처리 단계
if trid == "H0GSCNI0" or trid == "H0GSCNI9" or trid == "H0GSCNI0" or trid == "H0GSCNI9":
aes_key = jsonObject["body"]["output"]["key"]
aes_iv = jsonObject["body"]["output"]["iv"]
print("### TRID [%s] KEY[%s] IV[%s]" % (trid, aes_key, aes_iv))

elif trid == "PINGPONG":
print("### RECV [PINGPONG] [%s]" % (data))
await websocket.send(data)
print("### SEND [PINGPONG] [%s]" % (data))



if trid0 == "H0GSCNI0" or trid0 == "H0GSCNI9": # 해외주실체결 통보 처리
stocksigningnotice_overseas(recvstr[3], aes_key, aes_iv)

else:

jsonObject = json.loads(data)
trid = jsonObject["header"]["tr_id"]

if trid != "PINGPONG":
rt_cd = jsonObject["body"]["rt_cd"]

if rt_cd == '1': # 에러일 경우 처리

if jsonObject["body"]["msg1"] != 'ALREADY IN SUBSCRIBE':
print("### ERROR RETURN CODE [ %s ][ %s ] MSG [ %s ]" % (jsonObject["header"]["tr_key"], rt_cd, jsonObject["body"]["msg1"]))
break

elif rt_cd == '0': # 정상일 경우 처리
print("### RETURN CODE [ %s ][ %s ] MSG [ %s ]" % (jsonObject["header"]["tr_key"], rt_cd, jsonObject["body"]["msg1"]))

# 체결통보 처리를 위한 AES256 KEY, IV 처리 단계
if trid == "H0GSCNI0": # 해외주식
aes_key = jsonObject["body"]["output"]["key"]
aes_iv = jsonObject["body"]["output"]["iv"]
print("### TRID [%s] KEY[%s] IV[%s]" % (trid, aes_key, aes_iv))

elif trid == "PINGPONG":
print("### RECV [PINGPONG] [%s]" % (data))
print("### SEND [PINGPONG] [%s]" % (data))

except websockets.ConnectionClosed:
continue


# 비동기로 서버에 접속한다.
asyncio.get_event_loop().run_until_complete(connect())
asyncio.get_event_loop().close()
asyncio.get_event_loop().close()

0 comments on commit dbe63dd

Please sign in to comment.