선물 실시간 데이터를 받을 일이 생겼습니다. 기존 xing api로 작업을 해서 돌리고 있는데, Open API에 실시간 TR이 있다는 말을 듣고 확인해보았습니다.

 

websocket을 이용하는 방식이라 개발하기 상당히 쉽게 되어 있습니다. 반면에 xing api는 callback 설정하고 등등 절차가 상당히 복잡합니다. 향후 기능 추가를 생각해서 이번 기회에 Open Api로 바꾸기로 했습니다.

 

ebest open api 사이트에 가면 실시간 TR 사용법에 대하여 기술되어 있는 글이 있습니다.

https://openapi.ebestsec.co.kr/howto-sample 

 

전체적인 흐름을 잘 정리해놓았으나 결정적으로 함수를 부르는 main 부분이 없습니다. 

 

그래서 동작하는 전체 소스를 공유하고자 합니다. Open API를 이용하여 실시간 데이터를 받고자 하는 경우에 유용하게 사용될 것입니다.

 

import requests
import json
import time
import asyncio
import websockets

APP_KEY = "본인의 key"
SECRET_KEY = "본인의 sec key"

 

우선 필요한 package import한 후 본인의 Open API 키를 넣습니다.  만약 관련 package가 없다고 나오면 아래와 같이 설치합니다.

 

pip install websockets

pip install asyncio

 

아래 코드는 그냥 묻지도 따지지도 말고 그냥 사용합니다.

# 이하 수정할 필요없는 부분
BASE_URL        = "https://openapi.ebestsec.co.kr:8080"
BASE_URL_WEBS   = "wss://openapi.ebestsec.co.kr:9443/websocket"

   
# 파생인의 쉼터 꿈에님 코드 인용
def get_token():
    PATH = "/oauth2/token"
    headers = {"content-type": "application/x-www-form-urlencoded"}
    body = {
        "appkey": APP_KEY,
        "appsecretkey": SECRET_KEY,
        "grant_type": "client_credentials",
        "scope": "oob"
    }
    result = requests.post(BASE_URL+PATH, headers=headers, data=body)

    body = result.json()

    return body["access_token"]


# 선물 실시간 시세용 message
def reg_future_real(cd, ticker):
    dt = {
        'header': {
            "token": get_token(),
            "tr_type": "3"  #3:실시간 등록
        },  
        'body' : {
            "tr_cd": cd,
            "tr_key": ticker,     
        }         
    }
    return json.dumps(dt) # json을 string으로 변환

지금 만들고자 하는 함수는 실시간 선물 시세입니다. 선물 실시간 체결이 되면 Open API를 통하여 아래 함수로 호출이 옵니다.

# 체결수량 출력
def on_future_sise(data):
    price    = float(data['price'])
    vol      = int(data['cvolume'])
    offerho1 = float(data['offerho1'])
    bidho1   = float(data['bidho1'])

    print(format(price, '5.2f'), format(vol, '4d'), format(offerho1, '5.2f'), format(bidho1, '5.2f'))

실제로 많은 정보들이 data에 들어옵니다. 자세한 정보는 KOSPI200 선물시세를 선택하면 나옵니다.

 

이제는 on_future_sise() 라는 함수가 호출되는 과정에 대하여 간단하게 정리합니다.

 

우선 코드부터 보죠.  KOSPI200 선물시세를 받을 수 있는 TR의 CODE는 'FC0'입니다. 

 

아래 real_api()라는 함수를 보면 async라는 문자가 앞에 있습니다. async with를 사용하는 경우도 있고, await와 함수명을 사용하는 경우도 있습니다. 비동기 함수를 사용하기 위한 절차라고 생각하시고 그냥 무시하셔도 됩니다. 앞으로 real_api 함수에서 connect/send/recv 부분은 손댈필요가 없기 때문입니다.

 

FUTURE_SISE       = 'FC0'

# 웹 소켓 관련 신경쓸 필요없음
import websockets
async def real_api(real_code, ticker):
    while True:
    # 웹 소켓에 접속을 합니다.
        async with websockets.connect(BASE_URL_WEBS) as websocket:
            str = reg_future_real(real_code, ticker)

            # 웹 소켓 서버로 데이터를 전송합니다.
            await websocket.send(str);
            print('wait')
            time.sleep(2)
            
            while True:
                # 웹 소켓 서버로 부터 메시지가 오면 콘솔에 출력합니다.
                data_s = await websocket.recv();
                data = json.loads(data_s)
                if data['body'] == None: # 시세가 바로 오지 않음 None이면 waiting
                    time.sleep(1)
                    continue
                if real_code == FUTURE_SISE:
                    on_future_sise(data['body'])

 

그래도 무슨 일을 하는지는 알아야겠지요?

reg_future_real() 함수는 실시간 TR을 등록하는 일을 합니다. 앞으로 이 함수에 등록하는 TR에서 주는 실시간 데이터를 받겠다는 의미입니다. 그 다음부터는 ebest server에서 전달하는 실시간 데이터를 받아서 사용할 함수로 전달하면 끝입니다.

 

이 중 특이한 부분은 websocket에서 받은 데이터를 json 형태로 변경시키는 아래 부분입니다. 실제로 recv한 data_s는 string 문자열입니다. 긴 문자열로 이루어진 데이터 중 원하는 값을 뽑아내기가 어렵기 때문에 json 형태로 변경해주는 절차가 필요합니다. 그게 바로 json.load입니다. 앞으로 data는 "key":value 형태로 접근이 가능합니다.

                data_s = await websocket.recv();
#                print(data_s)
                data = json.loads(data_s)

 

여기까지는 ebest sample에 나오는 내용과  비슷합니다.  결정적으로  ebest 문서에는 이렇게 많은 함수를 호출하는 부분이 빠져있는데요.

 

이렇게 만든 함수를 호출하는 방법은 다음과 같습니다.

if __name__ == '__main__':
    ticker = '101V3000'     # 2024년 3월 만기 선물
    cd = FUTURE_SISE
    asyncio.run(real_api(cd, ticker))

 

간단하죠.. 그냥 asyncio.run() 함수를 부르면 됩니다. 이때 인자로 위에서 만든 real_api(cd, ticker) 를 넣어줍니다. 즉 비동기적으로 real_api()를 실행하라의 의미입니다.

 

asyncio.run(real_api(cd, ticker))

 

결론적으로 websocket으로 연결하고 어쩌고 하는 부분은 모두 모르셔도 됩니다.

실제 선물이 체결되면 아래 함수로 data에 관련 정보가 저장된 상태로 아래 함수가 불리어진다는 것만 인지하면 됩니다.

def on_future_sise(data):

 

이 함수에서 여러 다양한 일들을 할 수 있습니다. 예를들어 10계약 이상 거래한 것만 출력하자 등등 (이건 다음 글에서 정리해보겠습니다.)

 

sample 소스코드는 아래 github에 있습니다.

https://github.com/multizone-quant/api_ex/blob/main/open_api_real_sample.py

 

 

------------

ebest open api 실시간 TR을 python으로 개발하는 방법을 간단하게 기술하였습니다.

다음에는 이러한 기본 코드를 바탕으로 빌드업을 해보겠습니다.

 

- 선물 거래량 n개 이상만 출력하기

- 선물 orderbook 실시간 정보 출력하기  

반응형

설정

트랙백

댓글