규도자 개발 블로그

파이썬으로 여러 개의 웹소켓에 동시에 연결하기 본문

Python/Python

파이썬으로 여러 개의 웹소켓에 동시에 연결하기

규도자 (gyudoza) 2021. 4. 20. 16:06
반응형

파이썬으로 여러 개의 웹소켓에 동시에 연결하기

토이프로젝트로 퀀트 프로그램을 하나 제작하고 있는데 맨 처음에는 각종 거래소에서 제공하는 api를 사용할까 하다가 초당 요청제한이라는 문턱에 걸렸다. 수학모델에 근거해서 전략의 타당성을 검토해야 하는데 수백종류의 암호화폐 데이터를 1초에 한번씩 api로 요청해 저장하려고 하니 터무니 없는 생각이긴 했다. 그렇다고 1분을 쪼개서 요청을 보내자니 엄청난 변동성의 암호화폐시장에서의 수학모델 분석에는 적절하지 않다는 생각이 들었다. 그래서 웹소켓을 찾아보니 다행스럽게도 거의 모든 거래소에서 웹소켓을 지원하고 있더라.
 만약에 다양한 플랫폼, 혹은 한 플랫폼에서도 다른 웹소켓 라우트에서 필요한 정보가 있으면 여러개의 웹소켓에 연결할 필요가 있다. 그럴 때 사용하기 좋은 코드이다.

import asyncio
import websockets
import json


async def upbit_ws_client(callback):
    uri = 'wss://api.upbit.com/websocket/v1'
    async with websockets.connect(uri) as websocket:
        subscribe_fmt = [
            {'ticket': 'test'},
            {
                'type': 'ticker',
                'codes': ['KRW-BTC'],
                'isOnlyRealtime': True
            },
            {'format': 'SIMPLE'}
        ]
        subscribe_data = json.dumps(subscribe_fmt)
        await websocket.send(subscribe_data)

        while True:
            print('111111111')
            await callback(await websocket.recv())


async def upbit_ws_client2(callback):
    uri = 'wss://api.upbit.com/websocket/v1'
    async with websockets.connect(uri) as websocket:
        subscribe_fmt = [
            {'ticket': 'test'},
            {
                'type': 'ticker',
                'codes': ['KRW-XRP'],
                'isOnlyRealtime': True
            },
            {'format': 'SIMPLE'}
        ]
        subscribe_data = json.dumps(subscribe_fmt)
        await websocket.send(subscribe_data)

        while True:
            print('2222222222')
            await callback(await websocket.recv())


async def response_message(*args, **kwargs):
    print(args)


if __name__ == '__main__':
    tasks = [
        asyncio.ensure_future(upbit_ws_client(response_message)),
        asyncio.ensure_future(upbit_ws_client2(response_message))
    ]
    asyncio.get_event_loop().run_until_complete(asyncio.wait(tasks))

이런식으로 구성하면 된다. 저 주소와 웹소켓으로 보내는 params만 조정하면 원하는 대로 쓸 수 있을 것이다. 사실 업비트에서 저 두 상품의 정보를 받아오는 데에는 그냥 한 개의 함수에 두 개의 params만 추가하면 된다.

 

async def upbit_ws_client2(callback):
    uri = 'wss://api.upbit.com/websocket/v1'
    async with websockets.connect(uri) as websocket:
        subscribe_fmt = [
            {'ticket': 'test'},
            {
                'type': 'ticker',
                'codes': ['KRW-XRP'],
                'isOnlyRealtime': True
            },
            {
                'type': 'ticker',
                'codes': ['KRW-BTC'],
                'isOnlyRealtime': True
            },
            {'format': 'SIMPLE'}
        ]
        subscribe_data = json.dumps(subscribe_fmt)
        await websocket.send(subscribe_data)

        while True:
            print('2222222222')
            await callback(await websocket.recv())

이런식으로 말이다. 하지만 코드를 보는 사람의 이해 + 전략노출을 방지하기 위해 이렇게 예제를 구성했다. 콜백함수가 실행되는 곳의 구분을 위해서도 print함수를 작성했다.

 맨 위에 있는 함수를 그대로 복사해다가 붙여넣기하고 실행해보면 잘 작동되는 코드를 확인할 수 있을 것이다. (패키지 인스톨은 필수)

 

이 사진이 맨 위에 있는 함수를 실행한 모습이다. 각 웹소켓이 11111과 22222로 구분되어 콜백함수가 잘 실행되는 모습을 확인해볼 수 있다.

 

반응형
2 Comments
  • 프로필사진 Nic.k 2021.10.29 02:34 안녕하세요 ! 좋은 글 잘봤습니다.

    웹소켓으로 받은 값을 함수에 매개변수로 넣으려면 어떻게 하나요 ?

    웹소켓 코드를 통해 가격을 받아오는 것 까지는 이해를 했는데 받아온 가격을 함수 처리하는걸 어떻게 할지 모르겠는데 알려주신다면 정말 감사하겠습니다.
  • 프로필사진 Favicon of https://this-programmer.tistory.com 규도자 (gyudoza) 2021.10.29 05:37 신고 위에있는 코드에서 알 수 있다시피 웹소켓에서 받아온 함수가 response_message라는 함수에서 실행되고 있다는 걸 알 수 있는데 args를 풀어서 보시면 사용할 수 있는 값이 들어있을 겁니다.

    결론은 response_message함수에서 처리하는 방법, 다른 함수를 콜백함수로 넘겨줘서 그 함수에서 처리하는 방법 두 개가 있습니다. 위 코드를 실행시켜보면 가격들이 출력되는 걸 알 수 있을텐데 그게 response_message에서 실행되고 있는 겁니다.
댓글쓰기 폼