Nếu bạn đang xây dựng bot giao dịch, ứng dụng theo dõi giá, hay đơn giản là muốn lấy dữ liệu thị trường tiền mã hóa một cách nhanh chóng và tiết kiệm tài nguyên, thì WebSocket chính là giải pháp bạn cần. Trong bài viết này, mình sẽ hướng dẫn bạn từng bước cách kết nối WebSocket của sàn OKX để nhận dữ liệu thị trường real-time, không cần kiến thức lập trình nâng cao.

WebSocket Là Gì Và Tại Sao Nên Dùng?

Trước khi đi vào phần kỹ thuật, mình muốn giải thích đơn giản để bạn hiểu:

REST API (kiểu gọi thông thường) hoạt động theo kiểu "hỏi - đáp": bạn gửi yêu cầu, server trả lời, rồi kết nối đóng lại. Nếu muốn cập nhật dữ liệu mới, bạn phải gửi yêu cầu lại. Cách này tốn tài nguyên và chậm khi cần dữ liệu liên tục.

WebSocket khác hoàn toàn: sau khi kết nối, server và client giữ "đường dây" mở với nhau. Mỗi khi có biến động giá, server tự động "đẩy" (push) dữ liệu đến bạn ngay lập tức mà không cần bạn phải hỏi. Điều này giúp:

Chuẩn Bị Trước Khi Bắt Đầu

Để thực hiện theo hướng dẫn này, bạn cần có:

Mình khuyên bạn nên tạo một thư mục riêng để lưu các file code, ví dụ: C:\okx_websocket\ trên Windows hoặc ~/okx_websocket/ trên macOS/Linux.

Cách Kết Nối WebSocket OKX - Hướng Dẫn Từng Bước

Bước 1: Cài Đặt Thư Viện Cần Thiết

Mở terminal (CMD trên Windows, Terminal trên macOS) và chạy lệnh sau để cài đặt thư viện websocket-client - đây là thư viện phổ biến nhất để làm việc với WebSocket trong Python:

pip install websocket-client

Sau khi cài đặt xong, bạn có thể kiểm tra bằng lệnh:

pip show websocket-client

Nếu thấy thông tin version hiển thị là OK.

Bước 2: Hiểu Cấu Trúc URL WebSocket OKX

OKX cung cấp nhiều endpoint WebSocket khác nhau cho các mục đích khác nhau:

URL WebSocket chính thức của OKX:

# Môi trường thực tế (Real Trading)
wss://ws.okx.com:8443/ws/v5/public

Môi trường demo (Testnet)

wss://ws.okx.com:8443/ws/v5/public?brokerId=9999

Lưu ý quan trọng: Port 8443 là port cho kết nối có mã hóa SSL. Bạn luôn nên dùng wss:// thay vì ws:// để đảm bảo dữ liệu được mã hóa an toàn.

Bước 3: Code Kết Nối WebSocket Đầu Tiên

Đây là code cơ bản nhất để kết nối WebSocket và nhận dữ liệu ticker (giá) của cặp BTC/USDT:

# okx_websocket_co_ban.py
import json
import websocket

def on_message(ws, message):
    """Hàm xử lý khi nhận được tin nhắn từ server"""
    data = json.loads(message)
    print("=" * 50)
    print("Dữ liệu nhận được:")
    print(json.dumps(data, indent=2, ensure_ascii=False))

def on_error(ws, error):
    """Hàm xử lý khi có lỗi xảy ra"""
    print(f"Lỗi: {error}")

def on_close(ws, close_status_code, close_msg):
    """Hàm xử lý khi kết nối đóng"""
    print("Kết nối đã đóng")

def on_open(ws):
    """Hàm xử lý khi kết nối mở - gửi yêu cầu đăng ký channel"""
    # Đăng ký nhận dữ liệu ticker BTC/USDT
    subscribe_message = {
        "op": "subscribe",
        "args": [{
            "channel": "tickers",
            "instId": "BTC-USDT"
        }]
    }
    ws.send(json.dumps(subscribe_message))
    print("Đã gửi yêu cầu đăng ký channel ticker BTC-USDT")

Tạo WebSocket App

ws = websocket.WebSocketApp( "wss://ws.okx.com:8443/ws/v5/public", on_message=on_message, on_error=on_error, on_close=on_close, on_open=on_open )

Chạy vòng lặp WebSocket (chạy mãi cho đến khi bạn tắt)

print("Đang kết nối đến OKX WebSocket...") ws.run_forever(ping_interval=30, ping_timeout=10)

Cách chạy: Lưu file lại và chạy python okx_websocket_co_ban.py. Bạn sẽ thấy dữ liệu giá BTC/USDT cập nhật liên tục mỗ khi có biến động.

Bước 4: Xem Dữ Liệu Trả Về

Khi kết nối thành công, dữ liệu bạn nhận được sẽ có cấu trúc tương tự như sau:

{
  "arg": {
    "channel": "tickers",
    "instId": "BTC-USDT"
  },
  "data": [{
    "instId": "BTC-USDT",
    "last": "67245.50",
    "lastSz": "0.123",
    "askPx": "67246.00",
    "askSz": "2.5",
    "bidPx": "67245.00",
    "bidSz": "1.8",
    "open24h": "66500.00",
    "high24h": "67800.00",
    "low24h": "66800.00",
    "volCcy24h": "125678.5432",
    "vol24h": "18543.21",
    "ts": "1703123456789",
    "sodUtc0": "66000.00",
    "sodUtc8": "66200.00"
  }]
}

Giải thích các trường quan trọng:

Các Channel Phổ Biến Khác

OKX cung cấp nhiều loại channel để bạn lấy dữ liệu khác nhau:

# Ví dụ: Đăng ký nhiều channel cùng lúc
def on_open(ws):
    subscribe_message = {
        "op": "subscribe",
        "args": [
            # Channel ticker - giá các cặp giao dịch
            {
                "channel": "tickers",
                "instId": "ETH-USDT"
            },
            # Channel klines - dữ liệu nến (biểu đồ)
            {
                "channel": "candle1m",
                "instId": "BTC-USDT"
            },
            # Channel orderbook - sổ lệnh
            {
                "channel": "books50",
                "instId": "BTC-USDT"
            }
        ]
    }
    ws.send(json.dumps(subscribe_message))
    print("Đã đăng ký 3 channel cùng lúc")

Code Hoàn Chỉnh Với Xử Lý Tự Động Reconnect

Trong thực tế, kết nối mạng có thể bị gián đoạn. Mình đã gặp nhiều lần server OKX ngắt kết nối đột ngột khi đang chạy bot giao dịch. Đây là code có tính năng tự động kết nối lại (reconnect) khi bị mất kết nối:

# okx_websocket_reconnect.py
import json
import time
import threading
import websocket

class OKXWebSocketClient:
    def __init__(self):
        self.ws = None
        self.url = "wss://ws.okx.com:8443/ws/v5/public"
        self.subscribed_channels = []
        self.is_running = False
        self.reconnect_interval = 5  # Giây chờ trước khi reconnect
        self.max_reconnect_attempts = 10
        self.reconnect_count = 0
        
    def on_message(self, ws, message):
        """Xử lý tin nhắn nhận được"""
        try:
            data = json.loads(message)
            
            # Kiểm tra nếu là phản hồi subscribe
            if "event" in data:
                if data["event"] == "subscribe":
                    print(f"✓ Đã đăng ký thành công: {data.get('channel')}")
                    return
                elif data["event"] == "error":
                    print(f"✗ Lỗi subscribe: {data.get('message')}")
                    return
            
            # Xử lý dữ liệu thực tế
            if "data" in data:
                channel = data["arg"]["channel"]
                inst_id = data["arg"]["instId"]
                
                if channel == "tickers":
                    ticker_data = data["data"][0]
                    price = ticker_data.get("last", "N/A")
                    change_24h = ticker_data.get("avg24h", "N/A")
                    volume = ticker_data.get("volCcy24h", "N/A")
                    print(f"[{inst_id}] Giá: ${price} | 24h Change: {change_24h}% | Vol: ${volume}")
                    
        except Exception as e:
            print(f"Lỗi xử lý message: {e}")
    
    def on_error(self, ws, error):
        """Xử lý lỗi WebSocket"""
        print(f"⚠ Lỗi WebSocket: {error}")
    
    def on_close(self, ws, close_status_code, close_msg):
        """Xử lý khi kết nối đóng"""
        print(f"Kết nối đã đóng: {close_status_code} - {close_msg}")
        self.is_running = False
        
    def on_open(self, ws):
        """Xử lý khi kết nối mở"""
        print("✓ Kết nối WebSocket thành công!")
        self.is_running = True
        self.reconnect_count = 0
        
        # Đăng ký các channel cần thiết
        subscribe_message = {
            "op": "subscribe", 
            "args": [
                {"channel": "tickers", "instId": "BTC-USDT"},
                {"channel": "tickers", "instId": "ETH-USDT"},
                {"channel": "tickers", "instId": "SOL-USDT"}
            ]
        }
        ws.send(json.dumps(subscribe_message))
    
    def start(self):
        """Bắt đầu kết nối WebSocket"""
        while self.reconnect_count < self.max_reconnect_attempts:
            try:
                print(f"Đang kết nối... (lần thử {self.reconnect_count + 1})")
                
                self.ws = websocket.WebSocketApp(
                    self.url,
                    on_message=self.on_message,
                    on_error=self.on_error,
                    on_close=self.on_close,
                    on_open=self.on_open
                )
                
                # Chạy WebSocket với auto-reconnect
                self.ws.run_forever(
                    ping_interval=30,
                    ping_timeout=10,
                    reconnect=5  # Tự động reconnect sau 5 giây nếu mất kết nối
                )
                
            except Exception as e:
                print(f"Lỗi kết nối: {e}")
                
            if self.is_running:
                break
                
            self.reconnect_count += 1
            print(f"Chờ {self.reconnect_interval} giây trước khi thử lại...")
            time.sleep(self.reconnect_interval)
        
        if self.reconnect_count >= self.max_reconnect_attempts:
            print("Đã hết số lần thử kết nối. Vui lòng kiểm tra internet!")

    def stop(self):
        """Dừng kết nối WebSocket"""
        if self.ws:
            self.ws.close()
            print("Đã dừng kết nối")

Sử dụng

if __name__ == "__main__": client = OKXWebSocketClient() try: print("=" * 60) print("OKX WebSocket Client - Nhận dữ liệu thị trường real-time") print("Nhấn Ctrl+C để dừng chương trình") print("=" * 60) client.start() except KeyboardInterrupt: print("\nĐang dừng chương trình...") client.stop()

Lỗi Thường Gặp Và Cách Khắc Phục

Lỗi 1: "Connection refused" Hoặc Không Kết Nối Được

Nguyên nhân: Firewall chặn port, URL sai, hoặc server OKX đang bảo trì.

Cách khắc phục:

# Kiểm tra URL chính xác (phải có wss:// và port 8443)
CORRECT_URL = "wss://ws.okx.com:8443/ws/v5/public"

Nếu dùng proxy, thêm cấu hình proxy

import os os.environ['http_proxy'] = 'http://your-proxy:port' os.environ['https_proxy'] = 'http://your-proxy:port'

Hoặc kiểm tra firewall

Trên Windows: kiểm tra Windows Defender Firewall

Trên Linux: sudo iptables -L

Lỗi 2: Phản Hồi "error" Khi Subscribe Channel

Nguyên nhân: Tên channel hoặc instId không đúng định dạng.

Cách khắc phục:

# Sai định dạng - dùng dấu gạch dưới

Channel sai: "ticker" thay vì "tickers"

instId sai: "BTCUSDT" thay vì "BTC-USDT"

Định dạng đúng:

CORRECT_CHANNEL = "tickers" # có "s" ở cuối CORRECT_INST_ID = "BTC-USDT" # dùng dấu gạch ngang "-"

Kiểm tra instId hợp lệ bằng cách gọi API lấy danh sách

import requests response = requests.get("https://www.okx.com/api/v5/market/instruments?instType=SPOT") instruments = response.json()["data"] print("Ví dụ instId hợp lệ:", instruments[0]["instId"])

Lỗi 3: Kết Nối Bị Ngắt Đột Ngột Sau Vài Phút

Nguyên nhân: OKX yêu cầu heartbeat/ping để giữ kết nối. Nếu không ping định kỳ, server sẽ tự động ngắt.

Cách khắc phục:

# Thêm ping_interval và ping_timeout khi khởi tạo
self.ws = websocket.WebSocketApp(
    url,
    on_message=self.on_message,
    on_error=self.on_error,
    on_close=self.on_close,
    on_open=self.on_open
)

run_forever với các tham số heartbeat

self.ws.run_forever( ping_interval=20, # Ping mỗi 20 giây (OKX khuyến nghị 20-30s) ping_timeout=10, # Timeout nếu không nhận phản hồi sau 10s reconnect=5 # Tự động reconnect sau 5 giây nếu mất kết nối )

Hoặc ping thủ công trong vòng lặp

def manual_ping(ws): while True: time.sleep(25) try: ws.ping() except: break

Lỗi 4: Dữ Liệu Trả Về Quá Nhiều, CPU Tăng Cao

Nguyên nhân: Đăng ký quá nhiều channel hoặc xử lý dữ liệu không tối ưu.

Cách khắc phục:

# Giới hạn độ sâu orderbook (thay vì lấy full 400 level)

Dùng "books5" thay vì "books400"

subscribe_message = { "op": "subscribe", "args": [{ "channel": "books5", # Chỉ lấy 5 mức giá bid/ask "instId": "BTC-USDT" }] }

Sử dụng threading để xử lý dữ liệu riêng biệt

from queue import Queue data_queue = Queue() def data_processor(): while True: data = data_queue.get() # Xử lý dữ liệu ở đây process_data(data) threading.Thread(target=data_processor, daemon=True).start()

Bảng Tổng Hợp Các Channel OKX WebSocket

Channel Mô Tả InstId Ví Dụ Tần Suất Cập Nhật
tickers Dữ liệu ticker đầy đủ BTC-USDT, ETH-USDT Real-time
candle1m Nến 1 phút BTC-USDT Cập nhật mỗi phút
candle1H Nến 1 giờ BTC-USDT Cập nhật mỗi giờ
books50 Orderbook 50 mức BTC-USDT Real-time
books5 Orderbook 5 mức BTC-USDT Real-time
trades Lịch sử giao dịch BTC-USDT Real-time

Phù Hợp Và Không Phù Hợp Với Ai

✓ WebSocket OKX Phù Hợp Với:

✗ WebSocket OKX Không Phù Hợp Với:

Mẹo Tối Ưu Hiệu Suất

Qua kinh nghiệm thực chiến của mình khi xây dựng nhiều bot giao dịch, đây là những mẹo giúp bạn tối ưu hiệu suất:

Kết Luận

Việc kết nối WebSocket của OKX không khó như bạn tưởng. Chỉ cần nắm vững cấu trúc URL, cách đăng ký channel, và xử lý dữ liệu trả về là bạn đã có thể nhận dữ liệu thị trường real-time một cách ổn định.

Điểm mấu chốt là phải luôn có cơ chế reconnectping heartbeat để duy trì kết nối lâu dài. Mình đã mất khá nhiều thời gian để tìm ra lỗi ngắt kết nối do thiếu ping, hy vọng bạn sẽ không gặp vấn đề tương tự.

Nếu bạn cần xử lý dữ liệu nhận được bằng AI (ví dụ phân tích cảm xúc thị trường, tạo tín hiệu giao dịch), hãy cân nhắc sử dụng dịch vụ API AI với chi phí thấp để tối ưu chi phí vận hành.

Chúc bạn thành công với dự án WebSocket của mình!


Bài viết được viết bởi đội ngũ HolySheep AI - Nền tảng API AI với chi phí tối ưu cho lập trình viên Việt Nam.

👉 Đăng ký HolySheep AI — nhận tín dụng miễn phí khi đăng ký