Skip to main content
Nhận bảng giá cổ phiếu cơ sở (HOSE, HNX, UPCOM) theo thời gian thực qua WebSocket. Bạn chỉ cần mở một kết nối duy nhất — server sẽ tự động đẩy dữ liệu mỗi khi có thay đổi. Dữ liệu bao gồm:
  • Sổ lệnh mua/bán top 3 (bid/offer)
  • Giá khớp, khối lượng khớp
  • Giá trần, sàn, tham chiếu
  • Room khối ngoại
  • Chỉ số (VN-INDEX, VN30…)
  • Giao dịch thỏa thuận
Trang này dành cho cổ phiếu cơ sở (endpoint /stream/normal). Nếu bạn cần bảng giá phái sinh, xem trang 7.2 — endpoint, channel ID và data type đều khác.

Demo tương tác

Địa chỉ WSS
Payload kết nối / xác thực
Kênh / Chủ đề
Demo trên chỉ mang tính minh họa. Protocol thực tế trên wire là TEXT frame phân tách bằng pipe (|), KHÔNG phải JSON. Xem các phần bên dưới để biết chi tiết format thật.

Kết nối

/ws/thesis/v1/stream/normal

WSS
Địa chỉ đầy đủ để kết nối:
BẮT BUỘC: Phải disable auto-ping (RFC 6455 ping frame) của WebSocket library. Server TCBS chỉ chấp nhận heartbeat dạng text frame d|p|||. Nếu library tự gửi binary ping → server trả 1002 Protocol Error và ngắt kết nối.
Cách disable auto-ping theo từng ngôn ngữ:

Xác thực (Authentication)

Sau khi kết nối WebSocket thành công, bạn phải gửi auth message trước khi subscribe bất kỳ kênh nào. Token OpenAPI cần được base64 encode trước khi gửi. Format auth message gửi tới server (xxx = base64 của token_openapi):
Ví dụ cụ thể với một token thực tế: Nếu auth thành công, server trả về:
Nếu auth thất bại, server trả về:
Ngoài ra, server cũng gửi bản tin cấu hình timeout d|33|15 — nghĩa là nếu client không gửi heartbeat trong 15 giây thì kết nối sẽ bị ngắt.
PHẢI đợi nhận response auth (d|0|{...success:true...}) trước khi gửi subscribe. Gửi subscribe ngay mà không đợi → có thể bị server reject.

Đăng ký kênh (Subscribe)

Sau khi auth thành công, bạn có 4 cách đăng ký dữ liệu tuỳ nhu cầu: theo mã, theo sàn, theo chỉ số, và theo thỏa thuận.

1. Theo mã cổ phiếu (tk)

Message subscribe theo mã gửi tới server:
Ví dụ: d|s|tk|bp+bi+tm+mp+op+fe|FPT,VCS,PNJ,PTB Bảng channel codes tương ứng với channel ID mà server trả về:

2. Theo sàn (ro)

Message subscribe theo sàn gửi tới server:
Ví dụ: d|s|ro|bp+bi+tm+mp+op+fe|1,2 — server sẽ trả về các channel s|1, s|2, s|3, s|4, s|5, s|6 như trên.

3. Theo chỉ số (si)

Message subscribe theo chỉ số gửi tới server:
Ví dụ: d|s|si|rt|1,2 — server trả về channel s|8 (rt / stock index). Bảng mã sàn / chỉ số (dùng cho cả ro và si):

4. Theo giao dịch thỏa thuận (pt)

Message subscribe thỏa thuận gửi tới server:
Ví dụ: d|s|pt|ptm+ptb+pts|1,2,3 — server trả về channel s|16 (pta) và s|17 (ptm). Mã sàn: 1-HOSE, 2-HNX, 3-UPCOM.

Huỷ đăng ký (Unsubscribe)

Để huỷ đăng ký, bạn dùng action u thay vì s. Cú pháp giống hoàn toàn lệnh subscribe. Format chung của message unsubscribe gửi tới server:

Ví dụ

Huỷ theo mã — message gửi tới server:
Huỷ theo sàn — message gửi tới server:
Huỷ theo chỉ số — message gửi tới server:
Huỷ giao dịch thỏa thuận — message gửi tới server:
Bạn có thể unsubscribe một phần mã. Ví dụ đang subscribe FPT,TCB,VCB mà muốn bỏ TCB → gửi d|u|tk|bp+bi+tm+mp+op+fe|TCB. Hai mã còn lại (FPT, VCB) vẫn tiếp tục nhận dữ liệu.

Lấy dữ liệu snapshot (Request)

Ngoài subscribe (nhận realtime liên tục), bạn có thể gửi lệnh request để lấy snapshot hiện tại một lần duy nhất mà không cần subscribe. Dùng action r. Format message request gửi tới server (lưu ý phần properties để trống — 2 dấu pipe liên tiếp ||):

Ví dụ

Request snapshot theo mã — message gửi tới server:
Server trả về channel s|38 (Tickers snapshot) chứa toàn bộ thông tin hiện tại của các mã bạn yêu cầu. Request snapshot theo sàn — message gửi tới server:
Server trả về snapshot toàn bộ mã trong sàn VN30.
Request chỉ trả về 1 lần (one-shot). Nếu bạn cần dữ liệu liên tục, hãy dùng subscribe. Request hữu ích khi khởi tạo UI hoặc đồng bộ lại state sau reconnect.

Lịch sử khớp trong ngày — tmh (Ticker Match History)

Ngoài các channel cơ bản (bi, op, fe, bp, mp, tm), bạn có thể subscribe thêm tmh để nhận lịch sử khớp lệnh trong ngày (tick-by-tick). Ví dụ subscribe có thêm tmh — message gửi tới server:
Khi subscribe tmh, server trả về channel s|22 (TickerMatchHis) chứa lịch sử khớp lệnh trong ngày cho mỗi mã.

Channel 22 — Ticker Match History (tmh)

Khi mới subscribe, server sẽ push toàn bộ lịch sử khớp lệnh trong ngày (backfill). Sau đó tiếp tục push realtime mỗi khi có khớp mới.

Heartbeat — Giữ kết nối

Client PHẢI gửi heartbeat text frame mỗi 2 giây. Nếu server không nhận heartbeat trong 15 giây → ngắt kết nối. Message heartbeat gửi tới server:
Heartbeat phải là TEXT frame, KHÔNG phải binary/ping frame. Đây là nguyên nhân #1 gây disconnect liên tục mà developer khó debug.

Cấu trúc Message

Server gửi 2 loại message, phân biệt qua prefix: Các control message thường gặp từ server: Format data message mà server trả về:
Ví dụ thực tế của một data message từ server:

Channel ID & Data Schema

Channel 1 — Bid Info (Sổ lệnh mua — Top 3)

Channel 2 — Offer Info (Sổ lệnh bán — Top 3)

Channel 3 — Foreign Exchange (Khối ngoại)

Channel 4 — Base Price (Giá trần/sàn/tham chiếu)

Channel 5 — Matched Price (Thông tin phiên)

Channel 6 — Ticker Match (Giao dịch khớp)

Channel 8 — Stock Index (Chỉ số)

Channel 16 — PT Advertisement (Chào mua/bán thỏa thuận)

Channel 17 — PT Match (Khớp thỏa thuận)

So sánh Channel ID: Cổ phiếu vs Phái sinh

Channel ID hoàn toàn khác giữa 2 endpoint, và data type cũng khác (cổ phiếu trả string cho giá/khối lượng, phái sinh trả number). KHÔNG dùng chung parser cho cổ phiếu và phái sinh.

Sequence Diagram — Luồng hoàn chỉnh


Xử lý lỗi & Reconnect

Nguyên nhân disconnect

Chiến lược reconnect (khuyến nghị)

Dùng exponential backoff: delay = min(2^attempt, 30) giây. Tối đa 10 lần thử, sau đó dừng lại và alert.

Ngoài giờ giao dịch

Phiên cơ sở: 9:00–11:30 (sáng) và 13:00–14:45 (chiều), có phiên ATC đến ~14:45–15:00 tuỳ sàn. Ngoài giờ thì bạn vẫn connect bình thường, heartbeat vẫn cần gửi, nhưng sẽ không có data message nào. Khi phiên sau mở, data tự chảy lại — không cần reconnect.

Code hoàn chỉnh


FAQ — Câu hỏi thường gặp

99% là do library tự gửi RFC ping frame. Phải disable auto-ping và tự gửi d|p||| mỗi 2s.
Bảng giá cơ sở trả string cho hầu hết trường giá và khối lượng (bi, op, fe, tm). Riêng bp, mp, rt trả number. Khuyến nghị: cast rõ ràng khi parse.
Dùng lệnh ro — ví dụ d|s|ro|bp+bi+tm+mp+op+fe|1,2 để nhận toàn bộ VN-INDEX và VN30-INDEX.
Subscribe bằng d|s|si|rt|1,2 và đọc channel s|8 (rt / stock index).
Được. Connection sống bình thường (vẫn cần heartbeat), nhưng không có data cho đến khi phiên mở (9:00).
Token hiệu lực tối đa 8 giờ. Server ngắt connection khi token hết hạn. Client cần detect disconnect → refresh token → reconnect.