WebSocket API
Truyền dữ liệu thời gian thực cho giao dịch quyền chọn Hypercall.
Xem Tài liệu tham khảo WebSocket API tương tác để có trải nghiệm duyệt tốt hơn với các ví dụ trực tiếp và chi tiết schema.
Tải đặc tả AsyncAPI để sử dụng theo hướng lập trình.
Kết nối
Kết nối tới wss://HOST/ws:
Các endpoint:
- Production:
wss://api.hypercall.xyz/ws - Local:
ws://localhost:3000/ws
Testnet tạm thời bị vô hiệu hóa cho đến khi Hypercall có thêm testnet HYPE.
Nhận diện ví
Để nhận dữ liệu trên các kênh yêu cầu xác thực (lệnh, khớp lệnh, danh mục), hãy nhận diện ví của bạn sau khi kết nối bằng cách gửi một thông điệp Authenticate:
{"type": "Authenticate", "wallet": "0x1234..."}
Máy chủ phản hồi bằng xác nhận:
{"type": "Authenticated", "wallet": "0x1234..."}
Sau khi nhận được Authenticated, bạn có thể đăng ký các kênh yêu cầu xác thực. Nếu địa chỉ ví không hợp lệ, máy chủ phản hồi bằng một thông điệp Error và kết nối vẫn được giữ mở.
Tham số truy vấn ?wallet= vẫn được hỗ trợ để tương thích ngược nhưng đã lỗi thời và sẽ bị loại bỏ trong một bản phát hành tương lai. Hãy ưu tiên phương pháp dựa trên thông điệp ở trên.
Tính sống của kết nối
Máy chủ thực thi một cơ chế heartbeat cho WebSocket:
- Gửi một khung điều khiển
Pingmỗi 20 giây - Chờ một khung
Pongtương ứng trong vòng 60 giây - Đóng kết nối với mã đóng
1008và lý dopong timeoutnếu client ngừng phản hồi
Các cài đặt WebSocket của trình duyệt xử lý ping/pong một cách tự động. Nhiều thư viện websocket Rust, bao gồm tungstenite và tokio-tungstenite, cũng xử lý ping/pong khung điều khiển giúp bạn. Hãy kiểm tra tài liệu thư viện của client trước khi thêm xử lý Pong thủ công. Các cài đặt tùy chỉnh hoặc raw socket phải phản hồi các khung Ping bằng Pong.
Khôi phục khi consumer chậm
Máy chủ đóng một kết nối /ws không thể xả hết dữ liệu gửi đi trong các ngưỡng an toàn đã cấu hình về số thông điệp, số byte đã mã hóa, tuổi hàng đợi, hoặc thời gian ghi socket. Khi kết nối vẫn có thể chấp nhận một khung đóng, máy chủ sử dụng mã 1008 và một lý do JSON gọn:
{"error":"slow_consumer","class":"ordered_public","cause":"message_age","recovery":"snapshot_resubscribe"}
Các trường lý do là:
| Trường | Ý nghĩa |
|---|---|
class | Lớp phân phối có khung vượt qua ranh giới an toàn. |
cause | message_limit, byte_limit, message_age, hoặc write_timeout. |
recovery | Hành động tiếp theo bắt buộc, chẳng hạn như resubscribe, snapshot_resubscribe, portfolio_refetch, hoặc rest_reconcile. |
Sau bất kỳ lần ngắt kết nối nào, hãy kết nối lại, nhận diện ví lần nữa khi cần, đăng ký lại, và đối chiếu trạng thái hiện tại trước khi xử lý các sự kiện mới. Các kênh công khai có thứ tự yêu cầu một snapshot mới. Các kênh sự kiện riêng tư yêu cầu đối chiếu qua bề mặt REST có thẩm quyền vì việc phát lại theo con trỏ (cursor) chưa khả dụng. Một kết nối bị đình trệ hoàn toàn có thể chấm dứt trước khi đọc được lý do đóng, nên client cũng phải sử dụng luồng khôi phục này cho một lần đóng không sạch.
Hãy dùng các kết nối riêng biệt cho dữ liệu thị trường công khai tốc độ cao và cho các lệnh yêu cầu xác thực hoặc các luồng riêng tư. Các lớp phân phối chọn số liệu và hành vi khôi phục, nhưng các khung trên một kết nối vẫn dùng chung một đường ghi socket có thứ tự. Do đó một lần ghi công khai bị đình trệ có thể làm chậm các khung riêng tư sau đó trên cùng kết nối đó cho đến khi hạn chót ghi đóng nó lại.
Đăng ký kênh
Gửi một thông điệp JSON để đăng ký:
{"type": "Subscribe", "channel": "orderbook"}
Để hủy đăng ký:
{"type": "Unsubscribe", "channel": "orderbook"}
Bạn sẽ nhận được một xác nhận:
{"type": "Subscribed", "channel": "orderbook"}
Lọc theo symbol
Các kênh order_updates và fills hỗ trợ một bộ lọc symbols tùy chọn. Khi được cung cấp, máy chủ chỉ gửi các thông điệp có tài sản cơ sở khớp với một trong các symbol được chỉ định.
{"type": "Subscribe", "channel": "order_updates", "symbols": ["BTC"]}
Cả tài sản cơ sở đơn thuần ("BTC") và tên instrument đầy đủ ("BTC-20260131-100000-C") đều được chấp nhận. Để thêm nhiều symbol hơn, hãy gửi một Subscribe khác. Để loại bỏ các symbol cụ thể:
{"type": "Unsubscribe", "channel": "order_updates", "symbols": ["BTC"]}
Khi không có symbols nào được chỉ định, tất cả cập nhật cho ví của bạn sẽ được chuyển tiếp.
Lọc chuỗi quyền chọn
Kênh options_chain hỗ trợ lọc theo tài sản cơ sở, ngày đáo hạn, và loại quyền chọn:
{
"type": "Subscribe",
"channel": "options_chain",
"symbols": ["BTC-20260131-100000-C"],
"expiry": "2026-01-31",
"option_type": "call"
}
| Bộ lọc | Giá trị | Mặc định |
|---|---|---|
symbols | Mảng các symbol instrument đầy đủ (ví dụ, ["BTC-20260131-100000-C"]) | Tất cả instrument |
expiry | Chuỗi ngày "YYYY-MM-DD" | Tất cả ngày đáo hạn |
option_type | "call", "put", hoặc bỏ trống để lấy cả hai | Cả hai |
Các kênh khả dụng
| Kênh | Yêu cầu xác thực | Mô tả |
|---|---|---|
orderbook | Không | Cập nhật sổ lệnh L2 cho tất cả symbol |
trades | Không | Luồng giao dịch công khai |
market_updates | Không | Thay đổi niêm yết thị trường (tạo/xóa/hết hạn) |
options_chain | Không | Cập nhật chuỗi quyền chọn theo gia tăng (có thể lọc theo symbols, expiry, option_type) |
index_prices | Không | Giá spot/chỉ số thời gian thực cho tất cả tài sản cơ sở |
indicative_market_data | Không | Luồng nhà cung cấp báo giá trong allowlist. Chưa khả dụng rộng rãi |
order_updates | Có | Thay đổi trạng thái lệnh của bạn (có thể lọc theo symbol) |
fills | Có | Các lần khớp lệnh của bạn (có thể lọc theo symbol) |
portfolio | Có | Cập nhật vị thế và số dư của bạn |
liquidation | Có | Thay đổi trạng thái thanh lý của bạn |
competition | Có | Tóm tắt PnL, thứ hạng, và thống kê cuối cùng của cuộc thi của bạn |
competition_engagement | Có | Thay đổi thứ hạng, khoảng cách tới hạng kế tiếp, và bảng xếp hạng cuối cùng |
rfq | Có | Báo giá RFQ, cập nhật trạng thái, và thông báo khớp lệnh |
Các loại thông điệp
Đặt lệnh (Yêu cầu xác thực)
Đặt một lệnh qua đường lệnh WebSocket.
{
"type": "PlaceOrder",
"wallet": "0x1234...",
"symbol": "BTC-20260131-100000-C",
"side": "Buy",
"size": "1",
"price": "100",
"tif": "gtc",
"route": "book_only",
"client_id": "my-order-1",
"nonce": 1000,
"signature": "0x..."
}
| Trường | Kiểu | Mô tả |
|---|---|---|
wallet | string | Địa chỉ ví sở hữu lệnh |
symbol | string | Symbol quyền chọn |
side | string | "Buy" hoặc "Sell" |
size | string | Quy mô hợp đồng, khớp chính xác với giá trị đã ký |
price | string | Giá giới hạn, khớp chính xác với giá trị đã ký |
tif | string | Time-in-force tùy chọn, mặc định là "gtc" |
route | string | Route tùy chọn. Dùng "book_only" cho các lệnh WebSocket nhận biết route. Route bỏ trống vẫn được chấp nhận cho đến ít nhất ngày 4 tháng 7, 2026. |
client_id | string | ID lệnh của client tùy chọn |
nonce | integer | Nonce ký duy nhất |
signature | string | Chữ ký EIP-712 PlaceOrder |
PlaceOrder qua WebSocket hiện gửi trực tiếp đến sổ lệnh. route="best_execution" và route="rfq_only" bị từ chối trên WebSocket vì đường này chưa chạy định tuyến RPI/RFQ. Dùng POST /order cho best_execution.
Cập nhật sổ lệnh
Snapshot/cập nhật sổ lệnh L2 cho một symbol.
{
"type": "OrderbookUpdate",
"symbol": "BTC-20260131-100000-C",
"bids": [["95000.5", "10.5"], ["94999.0", "25.0"]],
"asks": [["95001.0", "8.0"], ["95002.5", "15.0"]],
"timestamp": 1737331200000
}
| Trường | Kiểu | Mô tả |
|---|---|---|
symbol | string | Symbol quyền chọn |
bids | array | Các mức giá mua dưới dạng tuple [price, size], size tính theo hợp đồng ở dạng dễ đọc |
asks | array | Các mức giá bán dưới dạng tuple [price, size], size tính theo hợp đồng ở dạng dễ đọc |
timestamp | integer | Unix timestamp (mili giây) |
Giao dịch
Sự kiện giao dịch công khai.
{
"type": "Trade",
"symbol": "BTC-20260131-100000-C",
"price": "0.0523",
"size": "5.0",
"side": "buy",
"timestamp": 1737331200000
}
| Trường | Kiểu | Mô tả |
|---|---|---|
symbol | string | Symbol quyền chọn |
price | string | Giá giao dịch tính bằng USD |
size | string | Quy mô giao dịch tính bằng hợp đồng |
side | string | Phía chủ động (buy hoặc sell) |
timestamp | integer | Unix timestamp (mili giây) |
Khớp lệnh (Yêu cầu xác thực)
Thông báo khớp lệnh giao dịch của bạn.
{
"type": "Fill",
"order_id": 12345,
"fill_id": 67890,
"symbol": "BTC-20260131-100000-C",
"side": "buy",
"price": "0.0523",
"size": "5.0",
"timestamp": 1737331200000,
"wallet_address": "0x1234...abcd",
"fee": "0",
"trade_id": 99999,
"is_taker": true
}
| Trường | Kiểu | Mô tả |
|---|---|---|
order_id | integer | ID lệnh của bạn |
fill_id | integer | ID khớp lệnh |
symbol | string | Mã quyền chọn |
side | string | Chiều giao dịch (buy hoặc sell) |
price | string | Giá khớp tính bằng USD |
size | string | Khối lượng khớp tính bằng số hợp đồng |
timestamp | integer | Dấu thời gian Unix (mili giây) |
wallet_address | string | Địa chỉ ví của bạn |
fee | string | Phí giao dịch được thu. Trả về 0 khi phí của sàn giao dịch launch venue bị tắt |
trade_id | integer | ID giao dịch duy nhất |
is_taker | boolean | Bạn có phải là bên taker hay không |
builder_code_address | string? | Ví builder code (nếu có) |
builder_code_fee | string? | Phí builder code. Trả về null khi phí của sàn giao dịch launch venue bị tắt |
Cập nhật Danh mục (Đã xác thực)
Cập nhật luồng danh mục cho các vị thế, số dư, ký quỹ và các Greeks.
Ví dụ cập nhật Greeks:
{
"type": "PortfolioUpdate",
"timestamp": 1737331200000,
"per_leg": [
{
"symbol": "BTC-20260131-100000-C",
"quantity": "2.0",
"delta": 0.91,
"gamma": 0.003,
"theta": -0.12,
"vega": 0.44,
"iv": 0.63
}
],
"aggregate": {
"delta": 0.91,
"gamma": 0.003,
"theta": -0.12,
"vega": 0.44,
"iv": 0.63
}
}
Đối với danh mục trống, các cập nhật Greeks sử dụng:
per_leg: []aggregate: null
Tóm tắt PnL Cuộc thi (Đã xác thực)
Cập nhật luồng cuộc thi để hiển thị PnL ở header/footer.
{
"type": "CompetitionPnlSummary",
"wallet_address": "0x1234...abcd",
"lifetime_realized_pnl": "1250.50",
"active_competition": {
"competition_id": 7,
"competition_name": "Spring Sprint",
"competition_state": "active",
"rank": 12,
"pnl": "420.25",
"volume": "25000",
"efficiency": "0.01681",
"medal": null
},
"timestamp": 1737331200000
}
Khi không có cuộc thi nào đang diễn ra, active_competition là null.
Cập nhật Lệnh (Đã xác thực)
Thông báo thay đổi trạng thái lệnh.
{
"type": "OrderUpdate",
"order_id": 12345,
"client_order_id": "my-order-1",
"status": "filled",
"filled_size": "10.0",
"remaining_size": "0",
"avg_fill_price": "0.0523"
}
Cập nhật Thị trường
Thay đổi về danh sách thị trường.
Thị trường Được tạo:
{
"type": "MarketUpdate",
"action": "Created",
"symbol": "BTC-20260131-100000-C",
"strike": "100000",
"is_call": true,
"underlying": "BTC",
"expiry": 1738281600,
"timestamp": 1737331200000
}
Thị trường Đã đáo hạn:
{
"type": "MarketUpdate",
"action": "Expired",
"symbol": "BTC-20260131-100000-C",
"strike": "100000",
"is_call": true,
"underlying": "BTC",
"expiry": 1738281600,
"timestamp": 1738281600000
}
Vị thế Đã đáo hạn (Đã xác thực)
Thông báo khi vị thế của bạn được thanh toán tại ngày đáo hạn.
{
"type": "PositionExpired",
"wallet_address": "0x1234...abcd",
"symbol": "BTC-20260131-100000-C",
"position_size": "10.0",
"settlement_price": "105000",
"settlement_value": "500.0",
"timestamp": 1738281600000
}
Thay đổi Trạng thái Thanh lý (Đã xác thực)
Thay đổi trạng thái thanh lý tài khoản của bạn.
{
"type": "LiquidationStateChange",
"wallet_address": "0x1234...abcd",
"previous_state": "Normal",
"new_state": "Warning",
"equity": "10000.0",
"mm_required": "9500.0",
"shortfall": "0",
"auction_id": null,
"timestamp": 1737331200000
}
| Trạng thái | Mô tả |
|---|---|
Normal | Tài khoản đang lành mạnh |
Warning | Sắp bị margin call |
Liquidating | Phiên đấu giá thanh lý đang diễn ra |
Cập nhật Giá Chỉ số
Giá spot/chỉ số được gộp theo lô cho tất cả các tài sản cơ sở.
{
"type": "IndexPriceUpdate",
"prices": [
{"underlying": "BTC", "price": "97250.50"},
{"underlying": "ETH", "price": "3200.00"},
{"underlying": "HYPE", "price": "28.50"}
],
"timestamp": 1737331200000
}
| Trường | Kiểu | Mô tả |
|---|---|---|
prices | array | Mảng các mục {underlying, price} cho mỗi tài sản cơ sở được theo dõi |
prices[].underlying | string | Mã tài sản cơ sở (ví dụ: "BTC", "ETH") |
prices[].price | string | Giá spot/chỉ số hiện tại tính bằng USD |
timestamp | integer | Dấu thời gian Unix (mili giây) |
Dữ liệu Thị trường Tham khảo
Luồng nhà cung cấp báo giá trong danh sách được cho phép, với giá mua/giá bán tốt nhất được tổng hợp từ các nhà cung cấp báo giá đã đăng ký. Kênh này chưa được cung cấp rộng rãi. Hãy sử dụng dữ liệu thị trường REST và các kênh lệnh/khớp lệnh/danh mục đã xác thực, trừ khi Hypercall đã bật tính năng luồng nhà cung cấp báo giá cho tích hợp của bạn.
{
"type": "IndicativeMarketData",
"instrument": "BTC-20260131-100000-C",
"best_bid": "0.0520",
"best_ask": "0.0530",
"indicative_bid_size": "50.0",
"indicative_ask_size": "25.0",
"num_providers": 3,
"timestamp": 1737331200000
}
| Trường | Kiểu | Mô tả |
|---|---|---|
instrument | string | Mã quyền chọn |
best_bid | string | Giá mua tổng hợp tốt nhất (tùy chọn) |
best_ask | string | Giá bán tổng hợp tốt nhất (tùy chọn) |
bid_iv | number | Biến động ngụ ý của giá mua tốt nhất (tùy chọn) |
ask_iv | number | Biến động ngụ ý của giá bán tốt nhất (tùy chọn) |
indicative_bid_size | string | Tổng khối lượng mua trên tất cả nhà cung cấp (tùy chọn) |
indicative_ask_size | string | Tổng khối lượng bán trên tất cả nhà cung cấp (tùy chọn) |
num_providers | integer | Số lượng nhà cung cấp báo giá đang hoạt động |
timestamp | integer | Dấu thời gian Unix (mili giây) |
Thay đổi Thứ hạng Cuộc thi (Đã xác thực)
Thông báo khi thứ hạng của bạn thay đổi trong một cuộc thi đang diễn ra.
{
"type": "CompetitionRankChange",
"wallet_address": "0x1234...abcd",
"competition_id": 7,
"from_rank": 15,
"to_rank": 12,
"delta_places": 3,
"pnl": "420.25",
"timestamp": 1737331200000
}
Cập nhật Khoảng cách Cuộc thi (Đã xác thực)
Khoảng cách đến thứ hạng ngay trên bạn.
{
"type": "CompetitionGapUpdate",
"wallet_address": "0x1234...abcd",
"competition_id": 7,
"rank": 12,
"next_rank": 11,
"gap_metric_value": "50.00",
"timestamp": 1737331200000
}
Thứ hạng Chung cuộc (Đã xác thực)
Được gửi khi một cuộc thi kết thúc kèm theo kết quả cuối cùng của bạn.
{
"type": "CompetitionFinalStanding",
"wallet_address": "0x1234...abcd",
"competition_id": 7,
"rank": 12,
"pnl": "420.25",
"volume": "25000",
"efficiency": "0.01681",
"medal": null,
"timestamp": 1737331200000
}
Báo giá RFQ (Đã xác thực)
Các báo giá nhận được để phản hồi cho yêu cầu RFQ mà bạn gửi.
{
"type": "RfqQuotes",
"rfq_id": "550e8400-e29b-41d4-a716-446655440000",
"quotes": [
{
"quote_id": "660e8400-e29b-41d4-a716-446655440001",
"net_premium": "52.30",
"expires_at": 1737331225000
}
],
"status": "quoted",
"taker_wallet": "0x1234...abcd"
}
Cập nhật Trạng thái RFQ (Đã xác thực)
Thay đổi trạng thái cho một RFQ mà bạn đã gửi.
{
"type": "RfqStatusUpdate",
"rfq_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "executed",
"taker_wallet": "0x1234...abcd"
}
Lỗi
Thông báo lỗi từ máy chủ.
{
"type": "Error",
"message": "Invalid channel: foobar"
}
Xác thực
Các kênh đã xác thực yêu cầu một tin nhắn định danh ví sau khi kết nối:
{"type": "Authenticate", "wallet": "0x1234567890abcdef..."}
Các tin nhắn trên các kênh đã xác thực được lọc để chỉ hiển thị dữ liệu cho ví của bạn. Không cần chữ ký cho các kết nối WebSocket.
Ví dụ: Python Client
import asyncio
import websockets
import json
async def main():
uri = "wss://api.hypercall.xyz/ws"
async with websockets.connect(uri) as ws:
# Identify the wallet before subscribing to authenticated channels.
await ws.send(json.dumps({
"type": "Authenticate",
"wallet": "0xYourWallet"
}))
# Subscribe to orderbook
await ws.send(json.dumps({
"type": "Subscribe",
"channel": "orderbook"
}))
# Subscribe to fills for BTC only
await ws.send(json.dumps({
"type": "Subscribe",
"channel": "fills",
"symbols": ["BTC"]
}))
# Listen for messages
async for message in ws:
data = json.loads(message)
print(f"Received: {data['type']}")
asyncio.run(main())
Ví dụ: TypeScript Client
const ws = new WebSocket("wss://api.hypercall.xyz/ws");
ws.onopen = () => {
ws.send(JSON.stringify({ type: "Authenticate", wallet: "0xYourWallet" }));
// Subscribe to channels
ws.send(JSON.stringify({ type: "Subscribe", channel: "orderbook" }));
// Subscribe to order updates filtered to BTC
ws.send(JSON.stringify({
type: "Subscribe",
channel: "order_updates",
symbols: ["BTC"],
}));
};
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
console.log(`Received: ${msg.type}`);
if (msg.type === "OrderbookUpdate") {
console.log(`${msg.symbol}: ${msg.bids.length} bids, ${msg.asks.length} asks`);
}
};