Skip to content

Instantly share code, notes, and snippets.

@esstory
Created Nov 17, 2017
Embed
What would you like to do?
CYBOS/CREON PLUS - 해외선물 잔고 실시간 잔고(잔고 및 현재가 실시간 반영) 예제
import sys
from PyQt5.QtWidgets import *
import win32com.client
from pandas import Series, DataFrame
import pandas as pd
import locale
import os
locale.setlocale(locale.LC_ALL, '')
# cp object
g_objCpStatus = win32com.client.Dispatch('CpUtil.CpCybos')
g_objCpTrade = win32com.client.Dispatch('CpTrade.CpTdUtil')
g_objCodeMgr = win32com.client.Dispatch("CpUtil.CpCodeMgr")
gExcelFile = 'ovfuturejango.xlsx'
# CpEvent: 실시간 이벤트 수신 클래스
class CpEvent:
def set_params(self, client, name, caller):
self.client = client # CP 실시간 통신 object
self.name = name # 서비스가 다른 이벤트를 구분하기 위한 이름
self.caller = caller # callback 을 위해 보관
def OnReceived(self):
if self.name == "ovfjango":
pbdata = {}
pbdata["처리구분"] = self.client.GetHeaderValue(2) # “00”-주문, “01”-정정, “02”-취소, “03”-체결
pbdata["code"] = self.client.GetHeaderValue(6) # 종목코드
pbdata["종목명"] = self.client.GetHeaderValue(7) # 종목코드
pbdata["매매구분"] = self.client.GetHeaderValue(8) # 매매구분
pbdata["잔고수량"] = self.client.GetHeaderValue(9) # 잔고수량
pbdata["단가"] = self.client.GetHeaderValue(10) # 단가
pbdata["청산가능"] = self.client.GetHeaderValue(11) # 청산가능수량
pbdata["미체결수량"] = self.client.GetHeaderValue(12) # 미체결수량
pbdata["현재가"] = self.client.GetHeaderValue(13) # 현재가
pbdata["대비부호"] = self.client.GetHeaderValue(14) # 전일대비부호
pbdata["전일대비"] = self.client.GetHeaderValue(15) # 전일대비
pbdata["전일대비율"] = self.client.GetHeaderValue(16) # 전일대비율
pbdata["평가금액"] = self.client.GetHeaderValue(17) # 평가금액
pbdata["평가손익"] = self.client.GetHeaderValue(18) # 평가손익
pbdata["손익률"] = self.client.GetHeaderValue(19) # 손익률
pbdata["매입금액"] = self.client.GetHeaderValue(20) # 매입금액
pbdata["승수"] = self.client.GetHeaderValue(21) # 승수
pbdata["통화코드"] = self.client.GetHeaderValue(23) # 통화코드
print(pbdata)
self.caller.updateContract(pbdata)
if self.name == "ovfucur":
# 현재가 체결 데이터 실시간 업데이트
code = self.client.GetHeaderValue(0)
self.caller.mstData[code]['cur'] = self.client.GetHeaderValue(7)
self.caller.mstData[code]['open'] = self.client.GetHeaderValue(14)
self.caller.mstData[code]['high'] = self.client.GetHeaderValue(15)
self.caller.mstData[code]['low'] = self.client.GetHeaderValue(16)
self.caller.mstData[code]['offer'] = self.client.GetHeaderValue(22) # 매도호가
self.caller.mstData[code]['bid'] = self.client.GetHeaderValue(23) # 매수호가
self.caller.mstData[code]['diff'] = self.client.GetHeaderValue(9) # 대비
self.caller.mstData[code]['vol'] = self.client.GetHeaderValue(11) # 거래량
print('체결실시간', self.caller.mstData[code])
self.caller.updatePrice(code)
elif self.name == "ovfubid":
code = self.client.GetHeaderValue(0)
sindx = 5
for i in range(1, 6):
offerkey = 'offer' + str(i)
bidkey = 'bid' + str(i)
self.caller.mstData[code][offerkey] = self.client.GetHeaderValue(sindx)
self.caller.mstData[code][bidkey] = self.client.GetHeaderValue(sindx + 3)
sindx += 6
#print('5차호가실시간', self.caller.mstData[code])
class CpPublish:
def __init__(self, name, serviceID):
self.name = name
self.obj = win32com.client.Dispatch(serviceID)
self.bIsSB = False
def Subscribe(self, var, caller):
if self.bIsSB:
self.Unsubscribe()
if (len(var) > 0):
self.obj.SetInputValue(0, var)
handler = win32com.client.WithEvents(self.obj, CpEvent)
handler.set_params(self.obj, self.name, caller)
self.obj.Subscribe()
self.bIsSB = True
def Unsubscribe(self):
if self.bIsSB:
self.obj.Unsubscribe()
self.bIsSB = False
class CpPBOvfJango(CpPublish):
def __init__(self):
super().__init__('ovfjango', 'CpForeDib.OvFutBalance')
class CpPBOvFuCur(CpPublish):
def __init__(self):
super().__init__("ovfucur", "CpForeDib.OvFutCur")
class CpPBOvFuOBid(CpPublish):
def __init__(self):
super().__init__("ovfubid", "CpForeDib.OvFutBid")
# 해외선물 현재가 조회
class CpRPOvForMst:
def __init__(self):
if (g_objCpStatus.IsConnect == 0):
print("PLUS가 정상적으로 연결되지 않음. ")
return
self.objMst = win32com.client.Dispatch("CpForeDib.OvFutMst")
self.objCur = CpPBOvFuCur()
self.objBid = CpPBOvFuOBid()
return
def Request(self, code, caller):
# 현재가 통신
self.objCur.Unsubscribe()
self.objBid.Unsubscribe()
self.objMst.SetInputValue(0, code)
ret = self.objMst.BlockRequest()
if self.objMst.GetDibStatus() != 0:
print("통신상태", self.objMst.GetDibStatus(), self.objMst.GetDibMsg1())
return False
self.objCur.Subscribe(code, caller)
self.objBid.Subscribe(code, caller)
# 수신 받은 현재가 정보를 rtMst 에 저장
caller.mstData[code] = {}
caller.mstData[code]['cur'] = self.objMst.GetHeaderValue(29)
caller.mstData[code]['open'] = self.objMst.GetHeaderValue(35)
caller.mstData[code]['high'] = self.objMst.GetHeaderValue(36)
caller.mstData[code]['low'] = self.objMst.GetHeaderValue(37)
caller.mstData[code]['tick'] = self.objMst.GetHeaderValue(6) # 호가 단위
caller.mstData[code]['consize'] = self.objMst.GetHeaderValue(9) # 계약크기
caller.mstData[code]['float'] = self.objMst.GetHeaderValue(4) # 가격 소수점
caller.mstData[code]['jinb'] = self.objMst.GetHeaderValue(5) # 진법
caller.mstData[code]['offer'] = self.objMst.GetHeaderValue(33) # 매도호가
caller.mstData[code]['bid'] = self.objMst.GetHeaderValue(34) # 매수호가
caller.mstData[code]['diff'] = self.objMst.GetHeaderValue(31) # 대비
caller.mstData[code]['vol'] = self.objMst.GetHeaderValue(32) # 거래량
sindx = 62
for i in range(1, 6):
offerkey = 'offer' + str(i)
bidkey = 'bid' + str(i)
caller.mstData[code][offerkey] = self.objMst.GetHeaderValue(sindx)
caller.mstData[code][bidkey] = self.objMst.GetHeaderValue(sindx + 3)
sindx += 6
print(caller.mstData[code])
def UnSubscribe(self):
self.objCur.Unsubscribe()
self.objBid.Unsubscribe()
# 해외선물 잔고(미결제) 통신
class CpOvfJango:
def __init__(self):
self.acc = g_objCpTrade.AccountNumber[0] # 계좌번호
def Request(self, caller):
if (g_objCpStatus.IsConnect == 0):
print('PLUS가 정상적으로 연결되지 않음. ')
return False
# 해외선물 미결제 잔고
objRq = win32com.client.Dispatch('CpForeTrade.OvfNotPaymentInq')
objRq.SetInputValue(1, self.acc) # 계좌번호
while True :
objRq.BlockRequest()
# 현재가 통신 및 통신 에러 처리
rqStatus = objRq.GetDibStatus()
rqRet = objRq.GetDibMsg1()
print('통신상태', rqStatus, rqRet)
if rqStatus != 0:
return False
# 조회 건수
cnt = objRq.GetHeaderValue(0)
print(cnt)
if cnt == 0 :
break
for i in range(cnt):
item = {}
item['code'] = objRq.GetDataValue(3, i) # 코드
item['종목명'] = objRq.GetDataValue(4, i)
item['매매구분'] = objRq.GetDataValue(5, i)
item['잔고수량'] = objRq.GetDataValue(6, i)
item['단가'] = objRq.GetDataValue(7, i)
item['청산가능'] = objRq.GetDataValue(8, i)
item['미체결수량'] = objRq.GetDataValue(9, i)
item['현재가'] = objRq.GetDataValue(10, i)
item['전일대비'] = objRq.GetDataValue(11, i)
item['전일대비율'] = objRq.GetDataValue(12, i)
item['평가금액'] = objRq.GetDataValue(13, i)
item['평가손익'] = objRq.GetDataValue(14, i)
item['손익률'] = objRq.GetDataValue(15, i)
item['매입금액'] = objRq.GetDataValue(16, i)
item['승수'] = objRq.GetDataValue(17, i)
item['통화코드'] = objRq.GetDataValue(18, i)
key = (item['code'], item['매매구분'])
caller.ovfJangadata[key] = item
print(item)
if objRq.Continue == False :
print("연속 조회 여부: 다음 데이터가 없음")
break
# print(self.data)
class MyWindow(QMainWindow):
def __init__(self):
super().__init__()
self.bTradeInit = False
# 연결 여부 체크
if (g_objCpStatus.IsConnect == 0):
print("PLUS가 정상적으로 연결되지 않음. ")
return False
if (g_objCpTrade.TradeInit(0) != 0):
print("주문 초기화 실패")
return False
self.bTradeInit = True
self.pbContract = CpPBOvfJango()
self.setWindowTitle('PLUS API TEST')
self.setGeometry(300, 300, 300, 240)
# 해외선물 잔고
self.ovfJangadata = {}
# 해외선물 종목 데이터
# [종목] = {key:value} 식으로 저장
self.mstData = {}
self.mstObj = {}
nH = 20
btnPrint = QPushButton('DF Print', self)
btnPrint.move(20, nH)
btnPrint.clicked.connect(self.btnPrint_clicked)
nH += 50
btnExcel = QPushButton('엑셀 내보내기', self)
btnExcel.move(20, nH)
btnExcel.clicked.connect(self.btnExcel_clicked)
nH += 50
btnExit = QPushButton('종료', self)
btnExit.move(20, nH)
btnExit.clicked.connect(self.btnExit_clicked)
self.btnStart_clicked()
def btnStart_clicked(self):
self.pbContract.Unsubscribe()
obj = CpOvfJango()
obj.Request(self);
# 잔고에서 중복을 제거 하기 위해 set 으로 임시 저장
codelist = set()
for key,value in self.ovfJangadata.items():
codelist.add(key[0])
# 종목의 현재가 정보 요청
for code in codelist:
self.mstObj[code] = CpRPOvForMst()
self.mstObj[code].Request(code, self)
self.pbContract.Subscribe("",self)
def btnPrint_clicked(self):
for key,value in self.ovfJangadata.items():
print(key, value)
def btnExit_clicked(self):
self.pbContract.Unsubscribe()
exit()
def btnExcel_clicked(self):
if (len(self.ovfJangadata) == 0):
print('잔고 없음')
return
# df= pd.DataFrame(columns=self.ovfJangadata.keys())
isFirst = True
for k, v in self.ovfJangadata.items():
# 데이터 프레임의 컬럼은 데이터의 key 값으로 생성
if isFirst:
df = pd.DataFrame(columns = v.keys())
isFirst = False
df.loc[len(df)] = v
# Create a Pandas Excel writer using XlsxWriter as the engine.
writer = pd.ExcelWriter(gExcelFile, engine='xlsxwriter')
# Convert the dataframe to an XlsxWriter Excel object.
df.to_excel(writer, sheet_name='Sheet1')
# Close the Pandas Excel writer and output the Excel file.
writer.save()
os.startfile(gExcelFile)
return
# 실시간 주문 체결 업데이트
def updateContract(self, pbdata):
key = (pbdata['code'], pbdata['매매구분'])
code = key[0]
print(key)
# 새로운 잔고 추가
if key not in self.ovfJangadata.keys() :
print(key, '찾기 실패')
if pbdata["잔고수량"] == 0:
return
item = {}
item['code'] = pbdata['code']
item['종목명'] = pbdata['종목명']
item['매매구분'] = pbdata['매매구분']
item['잔고수량'] = pbdata['잔고수량']
item['단가'] = pbdata['단가']
item['청산가능'] = pbdata['청산가능']
item['미체결수량'] = pbdata['미체결수량']
item['현재가'] = pbdata['현재가']
item['전일대비'] = pbdata['전일대비']
item['전일대비율'] = pbdata['전일대비율']
item['평가금액'] = pbdata['평가금액']
item['평가손익'] = pbdata['평가손익']
item['손익률'] = pbdata['손익률']
item['매입금액'] = pbdata['매입금액']
item['승수'] = pbdata['승수']
item['통화코드'] = pbdata['통화코드']
self.ovfJangadata[key] = item
print('새로운 잔고 추가 -', key)
return
# 기존 잔고에 대한 처리
item = self.ovfJangadata[key]
item['잔고수량'] = pbdata['잔고수량']
item['청산가능'] = pbdata['청산가능']
if (pbdata["처리구분"] == '00'): # 주문 접수
print('주문 접수 -', key)
self.ovfJangadata[key] = item
if code not in self.mstObj:
self.mstObj[code] = CpRPOvForMst()
self.mstObj[code].Request(code, self)
return
if item['잔고수량'] == 0: # 잔고 삭제
del self.ovfJangadata[key]
print('잔고 삭제 -', key)
# 현재가 실시간 요청 정보 제거
self.mstObj[code].UnSubscribe()
del self.mstObj[code]
del self.mstData[code]
return
print('체결 업데이트-', key)
item['단가'] = pbdata['단가']
item['미체결수량'] = pbdata['미체결수량']
item['현재가'] = pbdata['현재가']
item['전일대비'] = pbdata['전일대비']
item['전일대비율'] = pbdata['전일대비율']
item['평가금액'] = pbdata['평가금액']
item['평가손익'] = pbdata['평가손익']
item['손익률'] = pbdata['손익률']
item['매입금액'] = pbdata['매입금액']
self.ovfJangadata[key] = item
return
def updatePrice(self, code):
# 해외선물 잔고 평가손익 업데이트
# 평가손익 = (평균가 - 현재가) / tick size * tick value * 수량
for key,value in self.ovfJangadata.items():
if (key[0] != code):
continue
print('평가손익 업데이트')
cur = self.mstData[code]['cur']
value['현재가'] = cur
value['전일대비'] = self.mstData[code]['diff']
value['전일대비율'] = (self.mstData[code]['diff'] / (cur - self.mstData[code]['diff']) * 100)
tickunit = g_objCodeMgr.GetTickUnit(code)
tickvalue = g_objCodeMgr.GetTickValue(code)
avg = value['단가'] / tickunit * tickvalue
cpr = cur / tickunit * tickvalue
value['평가금액'] = cpr
print(code, 'avg', avg, 'cpr', cpr, 'tickunit', tickunit, 'tickunit',tickvalue)
if (key[1] == 'S'): # 매도 잔고
value['평가손익'] = (avg - cpr) * value["잔고수량"]
print(code, value['평가손익'])
# avg = 잔고 평균가 / tick size * tickvalue
# cpr = 현재가 / ticsize * tick value
# 매도 평가 손익 = avg - cpr * 수량
elif (key[1] == 'B'): # 매수잔고
value['평가손익'] = (cpr - avg) * value["잔고수량"]
print('평가손익 변경:', code, value['평가손익'])
# avg = 잔고 평균가 / tick size * tickvalue
# cpr = 현재가 / ticsize * tick value
# 매수 평가 손익 = cpr - avg * 수량
return
if __name__ == '__main__':
app = QApplication(sys.argv)
myWindow = MyWindow()
myWindow.show()
app.exec_()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment