선물 실시간 데이터를 받을 일이 생겼습니다. 기존 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 requests

 

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

# 이하 수정할 필요없는 부분
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 실시간 정보 출력하기  

반응형

설정

트랙백

댓글

기존 Xing Api에 비하여 Open Api가 사용하기 간편합니다. 우선 32bit cuda 설치할 필요가 없는 것이 엄청난 장점이고요. 그외 코드가 간단하기 때문에 앞으로는 Open API를 주로 사용할 듯 합니다.

 

이번에는 Open API를 이용하여 선물 tick 데이터를 받는 방법에 관하여 정리합니다. 

간단하게 생각하고 개발을 시작했는데, tick 데이터를 받는 API에 버그가 있어서 회피 코드 만들고 확인하느라 시간이 좀 많이 걸렸습니다. API 버그는 이전 글 참고하세요.

 

Xing API도 마찬가지지만 Open API도 10분 최대 qeury는 200회 횟수 제한이 있습니다. 문제는 tick 데이터는 200회 이상 받아야 하는 점인데요. 10분 기다렸다가 남은 부분 받으면 되지만 10분 기다리는 것이 아까운 것 같아서 약간의 편법을 동원했습니다. 다시 실행하는 경우에는 다시 10분에 200회 다운이 가능하다는 점을 활용하여 200회 query 후 종료한 후 다시 실행하는 방식을 사용합니다.

 

다시 실행할 때 이전에 받던 시간 다음부터 받아야하기 때문에 과거 정보가 필요합니다. 이것은 실행 중에  생성했다가 삭제하므로 신경쓰지 않으셔도 됩니다.

그래서 download 프로그램을 2번 연속으로 실행하여야 하므로 프로그램에서 알려주는 메세지에 따라서 진행하시면 됩니다. python이 없으시다면 python 부터 설치하세요.

 

OpenAPI를 이용하기 위해서는 key를 생성해야합니다. 아래 글은 꿈에님의 글에서 캡쳐해왔습니다.

 

KEY를 발급받으셨다고 가정하고 사용방법을 설명합니다.

 

우선 아래 깃허브에서 파일 두개를 다운 받은 후 다음의 절차대로 실행하시면 됩니다.

 

1. pip install websockets

 

2. tick-down.py 파일을 열어서 본인의 KEY 정보 추가

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

 

3. down하고자 하는 일자와 ticker(참고로 선물 ticker는 mts에서 선물을 클릭해보면 나옵니다.)

    date   = '20240125'
    ticker = '101V3000'

4. tick-download.py 실행

   python tick-download.py
   한번 더 실행하라는 메세지가 나오면 "위 화살표"를 눌러서 한번 더 실행


5. download 끝났으면 tick-download .py 실행
   python tick-download.py


6. down 받은 tick data는 future_tick 폴더에 있음

 

실행화면입니다.

tick-down.py 첫 번째 실행

 

두 번째 실행

 

tick-merge 실행

 

사용하기 최대한 간단하게 만들었으니, 사용 중 문제가 생기면 댓글 달아주세요. 바로 조치하도록 하겠습니다.

 

그리고 중간에 download받은 각각의 파일은 future_tick_seq 폴더에 기록이 되는데 계속 파일이 쌓입니다. 주기적으로 들어가셔서 지워주세요.

 

merge된 최종 tick 데이타는 future_tick 폴더에 차곡차곡 쌓입니다.

 

Ebest API 오류로 우여곡절을 겪었으나 코드가 완성이 되어서 기쁩니다. 그 과정에 많은 도움을 주신 꾸준님과 OpenAPI 샘플을 공유해주신 꿈에님께도 감사드립니다. 

 

소스코드가 있는 곳

https://github.com/multizone-quant/api_ex/tree/main

 

 

반응형

설정

트랙백

댓글