실시간 금융 시장 데이터 WebSocket API 연동 및 구독 가이드

실시간 금융 데이터 API 개요

금융 시장 데이터(미국 주식, 홍콩 주식, 중국 A주, 외환, 암호화폐, 원자재 등)를 실시간으로 수집하기 위해서는 WebSocket 기반의 스트리밍 API를 연동해야 합니다. 이 가이드에서는 WebSocket 연결 수립, 인증 토큰 처리, 실시간 시세 구독 및 수신 데이터 파싱에 대한 기술적 세부 사항을 다룹니다.

WebSocket 엔드포인트 및 인증

API에 접근하려면 발급받은 인증 토큰을 URL 파라미터로 전달하여 WebSocket 연결을 수립해야 합니다. 자산군에 따라 연결할 엔드포인트가 구분됩니다.

  • 외환, 암호화폐, 귀금속: wss://quote.tradeswitcher.com/quote-b-ws-api?token={YOUR_TOKEN}
  • 미국 및 홍콩 주식: wss://quote.tradeswitcher.com/quote-stock-b-ws-api?token={YOUR_TOKEN}

토큰은 서비스 제공자의 공식 포털에서 발급받을 수 있으며, 연결 후 세션 유지를 위해 주기적인 Ping/Pong 또는 하트비트 패킷을 전송해야 합니다.

Python을 이용한 WebSocket 클라이언트 구현

아래는 websocket-client 라이브러리를 사용하여 실시간 주가 및 오더북(Order Book) 데이터를 구독하는 Python 클라이언트 구현 예시입니다. 연결 수명 주기 관리와 하트비트 로직을 포함하도록 구조화되었습니다.


import json
import time
import threading
import websocket

class MarketDataStream:
    def __init__(self, endpoint_url, auth_token):
        self.ws_url = f"{endpoint_url}?token={auth_token}"
        self.socket = None
        self.heartbeat_interval = 15  # 하트비트 전송 주기 (초)

    def _send_heartbeat(self):
        """서버와의 연결 유지를 위해 주기적으로 하트비트 패킷을 전송합니다."""
        while self.socket and self.socket.keep_running:
            ping_payload = json.dumps({"cmd_id": 99999, "action": "ping"})
            self.socket.send(ping_payload)
            time.sleep(self.heartbeat_interval)

    def _on_ws_open(self, ws):
        print("[INFO] WebSocket 연결이 성공적으로 수립되었습니다.")
        
        # 하트비트 스레드 시작
        threading.Thread(target=self._send_heartbeat, daemon=True).start()

        # 실시간 체결 및 오더북 데이터 구독 요청
        subscription_request = {
            "cmd_id": 22002,
            "seq_id": 1001,
            "trace": "trace-uuid-8f7e6d5c-4b3a",
            "data": {
                "symbol_list": [
                    {"code": "AAPL.US", "depth_level": 5},
                    {"code": "0939.HK", "depth_level": 5}
                ]
            }
        }
        ws.send(json.dumps(subscription_request))
        print("[INFO] 시장 데이터 구독 요청이 전송되었습니다.")

    def _on_ws_message(self, ws, payload):
        """서버로부터 수신한 JSON 페이로드를 파싱합니다."""
        try:
            data = json.loads(payload)
            self._process_market_data(data)
        except json.JSONDecodeError:
            print(f"[ERROR] 잘못된 JSON 형식 수신: {payload}")

    def _process_market_data(self, data):
        """수신된 데이터의 명령어 ID(cmd_id)에 따라 적절한 처리를 수행합니다."""
        cmd = data.get("cmd_id")
        if cmd == 22998:
            print(f"[TRADE] {data['data']['code']} - 체결가: {data['data']['price']}")
        elif cmd == 22999:
            bids = data['data'].get('bids', [])
            asks = data['data'].get('asks', [])
            print(f"[DEPTH] {data['data']['code']} - 매수호가 1단계: {bids[0]['price'] if bids else 'N/A'}")
        elif cmd == 99999:
            pass  # 하트비트 응답 무시

    def _on_ws_error(self, ws, error):
        print(f"[ERROR] WebSocket 오류 발생: {error}")

    def _on_ws_close(self, ws, close_status_code, close_msg):
        print(f"[INFO] WebSocket 연결 종료: 코드={close_status_code}, 메시지={close_msg}")

    def connect(self):
        self.socket = websocket.WebSocketApp(
            self.ws_url,
            on_open=self._on_ws_open,
            on_message=self._on_ws_message,
            on_error=self._on_ws_error,
            on_close=self._on_ws_close
        )
        # 자동 재연결 및 무한 대기 실행
        self.socket.run_forever(reconnect=5)

if __name__ == "__main__":
    API_ENDPOINT = "wss://quote.tradeswitcher.com/quote-stock-b-ws-api"
    TOKEN = "YOUR_ACTUAL_TOKEN_HERE"
    
    stream = MarketDataStream(API_ENDPOINT, TOKEN)
    stream.connect()

수신 데이터 페이로드 구조 및 파싱

서버에서 푸시되는 데이터는 주로 최신 체결 정보와 오더북(호가창) 깊이 정보로 나뉩니다. 각 데이터는 cmd_id를 통해 식별됩니다.

1. 최신 체결 데이터 (Trade Tick)

cmd_id: 22998은 최신 시장 체결 내역을 나타냅니다.


{
    "cmd_id": 22998,
    "data": {
        "code": "AAPL.US",
        "seq": "1678886400000042",
        "tick_time": "1678886400",
        "price": "150.25",
        "volume": "150",
        "turnover": "22537.50",
        "trade_direction": 1
    }
}

2. 오더북 깊이 데이터 (Order Book Depth)

cmd_id: 22999는 매수(Bids) 및 매도(Asks) 호가창의 깊이 정보를 제공합니다.


{
    "cmd_id": 22999,
    "data": {
        "code": "0939.HK",
        "seq": "1678886400000099",
        "tick_time": "1678886400",
        "bids": [
            {"price": "5.10", "volume": "12000"},
            {"price": "5.09", "volume": "34000"},
            {"price": "5.08", "volume": "55000"},
            {"price": "5.07", "volume": "18000"},
            {"price": "5.06", "volume": "92000"}
        ],
        "asks": [
            {"price": "5.11", "volume": "15000"},
            {"price": "5.12", "volume": "28000"},
            {"price": "5.13", "volume": "41000"},
            {"price": "5.14", "volume": "22000"},
            {"price": "5.15", "volume": "85000"}
        ]
    }
}

태그: websocket python 금융API 실시간데이터 알고리즘트레이딩

9월 13일 02:13에 게시됨