Messages
{
"op": "subscribe",
"channel": "quotes",
"symbols": [
"600000.SH",
"000001.SZ"
]
}{
"op": "unsubscribe",
"channel": "depth",
"symbols": [
"600000.SH"
]
}{
"op": "subscribed",
"channel": "quotes",
"symbols": [
"600000.SH",
"000001.SZ"
],
"total": 2
}{
"op": "quotes",
"data": [
{
"symbol": "600000.SH",
"region": "CN",
"last_price": 9.72,
"prev_close": 9.78,
"open": 9.78,
"high": 9.78,
"low": 9.68,
"volume": 426585,
"amount": 422430500,
"timestamp": 1776754802000,
"ext": {
"type": "cn_equity",
"name": "浦发银行",
"change_pct": -0.006135,
"change_amount": -0.06,
"amplitude": 0.010225,
"turnover_rate": 0.001281
}
}
]
}{
"op": "depth",
"data": [
{
"symbol": "600000.SH",
"region": "CN",
"timestamp": 1776754802000,
"bid_prices": [
9.72,
9.71,
9.7,
9.69,
9.68
],
"bid_volumes": [
3192,
3870,
26168,
5849,
5480
],
"ask_prices": [
9.73,
9.74,
9.75,
9.76,
9.77
],
"ask_volumes": [
74,
1602,
1148,
1209,
1109
]
}
]
}{
"op": "error",
"message": "no permission for channel: depth"
}WebSocket 文档
WebSocket 实时推送
通过 WebSocket 订阅实时行情和市场深度推送
WSS
/
v1
/
ws
/
stream
概述
TickFlow 提供两个 WebSocket 接口:| 接口 | 地址 | 说明 |
|---|---|---|
| 统一推送(推荐) | /v1/ws/stream | 按频道订阅,支持 quotes(行情)和 depth(五档盘口) |
| 行情推送 | /v1/ws/quotes | 仅推送行情数据,兼容旧版 |
WebSocket 为付费功能,需要订阅包含 WebSocket 实时行情的套餐(如 Expert)或单独开启。市场深度频道额外需要「市场深度」权限。
统一推送 /v1/ws/stream
连接地址
wss://api.tickflow.org/v1/ws/stream?api_key=YOUR_API_KEY
api_key 查询参数认证。认证失败返回 HTTP 401/403,客户端应停止重连。
所有消息使用 JSON 文本帧。
客户端命令
subscribe — 订阅频道
按频道(channel)+ 标的列表(symbols)订阅。可多次调用追加。
{"op": "subscribe", "channel": "quotes", "symbols": ["600000.SH", "000001.SZ"]}
{"op": "subscribe", "channel": "depth", "symbols": ["600000.SH"]}
subscribed 确认,并立即推送新增标的的缓存快照。
支持的频道:
| 频道 | 说明 | 所需权限 |
|---|---|---|
quotes | 实时行情 | WebSocket 实时行情 |
depth | 五档市场深度 | 市场深度 |
unsubscribe — 退订频道
{"op": "unsubscribe", "channel": "depth", "symbols": ["600000.SH"]}
服务端消息
subscribed — 频道订阅状态
{"op": "subscribed", "channel": "quotes", "symbols": ["600000.SH", "000001.SZ"], "total": 2}
quotes — 行情推送
{
"op": "quotes",
"data": [
{
"symbol": "600000.SH",
"region": "CN",
"last_price": 9.72,
"prev_close": 9.78,
"open": 9.78,
"high": 9.78,
"low": 9.68,
"volume": 426585,
"amount": 422430500,
"timestamp": 1776754802000,
"ext": {
"type": "cn_equity",
"name": "浦发银行",
"change_pct": -0.006135,
"change_amount": -0.06,
"amplitude": 0.010225,
"turnover_rate": 0.001281
}
}
]
}
depth — 市场深度推送
{
"op": "depth",
"data": [
{
"symbol": "600000.SH",
"region": "CN",
"timestamp": 1776754802000,
"bid_prices": [9.72, 9.71, 9.7, 9.69, 9.68],
"bid_volumes": [3192, 3870, 26168, 5849, 5480],
"ask_prices": [9.73, 9.74, 9.75, 9.76, 9.77],
"ask_volumes": [74, 1602, 1148, 1209, 1109]
}
]
}
| 字段 | 说明 |
|---|---|
bid_prices | 买入价(买1-买5,降序) |
bid_volumes | 买入量 |
ask_prices | 卖出价(卖1-卖5,升序) |
ask_volumes | 卖出量 |
error — 错误消息
{"op": "error", "message": "no permission for channel: depth"}
no permission for channel: ...— 无该频道权限unknown channel: ...— 未知频道名exceeded max N symbols— 标的数超出套餐上限invalid message: ...— JSON 格式不正确
命令总览
| 客户端命令 | 说明 | 服务端响应 |
|---|---|---|
subscribe | 按频道订阅 | subscribed + 对应频道的缓存快照 |
unsubscribe | 按频道退订 | subscribed |
| 服务端推送 | 说明 | 触发条件 |
|---|---|---|
subscribed | 频道订阅状态 | 每次 subscribe / unsubscribe 后 |
quotes | 实时行情数据 | 已订阅标的有行情更新时 |
depth | 五档市场深度 | 已订阅标的盘口变化时 |
error | 错误信息 | 操作失败时 |
行情推送 /v1/ws/quotes(旧版)
旧版接口仅推送行情数据,不支持市场深度。新接入建议使用
/v1/ws/stream。连接地址
wss://api.tickflow.org/v1/ws/quotes?api_key=YOUR_API_KEY
协议
与统一推送的quotes 频道行为一致,但不使用 channel 字段:
{"op": "subscribe", "symbols": ["600000.SH", "000001.SZ"]}
{"op": "unsubscribe", "symbols": ["600000.SH"]}
quotes、subscribed、error 消息,格式与统一推送相同。
连接保活
服务端每 30 秒发送一次 Ping 帧,客户端需回复 Pong 帧。大多数 WebSocket 库会自动处理。连接管理
- 断开清理:连接断开后该连接的所有订阅自动清除
- 重连恢复:客户端断线重连后需重新发送
subscribe恢复订阅 - 认证错误:收到 HTTP 401/403 时不应自动重连,请检查 API Key 和套餐权限
代码示例
- Python
- JavaScript / Node.js
- Python SDK
使用 websockets 库连接统一推送:
pip install websockets
import asyncio
import json
import websockets
API_KEY = "your-api-key"
URL = f"wss://api.tickflow.org/v1/ws/stream?api_key={API_KEY}"
async def main():
async with websockets.connect(URL) as ws:
# 订阅行情和盘口
await ws.send(json.dumps({"op": "subscribe", "channel": "quotes", "symbols": ["600000.SH", "000001.SZ"]}))
await ws.send(json.dumps({"op": "subscribe", "channel": "depth", "symbols": ["600000.SH"]}))
async for raw in ws:
msg = json.loads(raw)
if msg["op"] == "subscribed":
print(f"[{msg['channel']}] 已订阅 {msg['total']} 个标的")
elif msg["op"] == "quotes":
for q in msg["data"]:
print(f"{q['symbol']}: {q['last_price']}")
elif msg["op"] == "depth":
for d in msg["data"]:
print(f"[盘口] {d['symbol']} 买1:{d['bid_prices'][0]} 卖1:{d['ask_prices'][0]}")
elif msg["op"] == "error":
print(f"错误: {msg['message']}")
asyncio.run(main())
const API_KEY = "your-api-key";
const URL = `wss://api.tickflow.org/v1/ws/stream?api_key=${API_KEY}`;
const ws = new WebSocket(URL);
ws.onopen = () => {
ws.send(JSON.stringify({ op: "subscribe", channel: "quotes", symbols: ["600000.SH"] }));
ws.send(JSON.stringify({ op: "subscribe", channel: "depth", symbols: ["600000.SH"] }));
};
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
if (msg.op === "subscribed") {
console.log(`[${msg.channel}] 已订阅 ${msg.total} 个标的`);
} else if (msg.op === "quotes") {
for (const q of msg.data) {
console.log(`${q.symbol}: ${q.last_price}`);
}
} else if (msg.op === "depth") {
for (const d of msg.data) {
console.log(`[盘口] ${d.symbol} 买1:${d.bid_prices[0]} 卖1:${d.ask_prices[0]}`);
}
} else if (msg.op === "error") {
console.error("错误:", msg.message);
}
};
ws.onerror = (err) => console.error("WebSocket error:", err);
ws.onclose = (e) => console.log("连接关闭:", e.code, e.reason);
TickFlow Python SDK 封装了连接管理、自动重连和订阅恢复:非阻塞模式:
pip install "tickflow[all]" --upgrade
from tickflow import TickFlow
tf = TickFlow(api_key="your-api-key")
stream = tf.stream
@stream.on_quotes
def on_quotes(quotes):
for q in quotes:
print(f"{q['symbol']}: {q['last_price']}")
@stream.on_depth
def on_depth(depths):
for d in depths:
print(f"[盘口] {d['symbol']} 买1:{d['bid_prices'][0]}×{d['bid_volumes'][0]}")
@stream.on_error
def on_error(msg):
print(f"错误: {msg}")
stream.subscribe("quotes", ["600000.SH", "000001.SZ"])
stream.subscribe("depth", ["600000.SH"])
stream.connect() # 阻塞直到 close() 或 Ctrl+C
stream.connect(block=False) # 后台线程运行
stream.subscribe("quotes", ["AAPL.US"]) # 动态追加订阅
如果只需获取某一时刻的行情快照,使用 REST 接口更为简单。WebSocket 适合需要持续接收行情更新的场景。
Messages
{
"op": "subscribe",
"channel": "quotes",
"symbols": [
"600000.SH",
"000001.SZ"
]
}{
"op": "unsubscribe",
"channel": "depth",
"symbols": [
"600000.SH"
]
}{
"op": "subscribed",
"channel": "quotes",
"symbols": [
"600000.SH",
"000001.SZ"
],
"total": 2
}{
"op": "quotes",
"data": [
{
"symbol": "600000.SH",
"region": "CN",
"last_price": 9.72,
"prev_close": 9.78,
"open": 9.78,
"high": 9.78,
"low": 9.68,
"volume": 426585,
"amount": 422430500,
"timestamp": 1776754802000,
"ext": {
"type": "cn_equity",
"name": "浦发银行",
"change_pct": -0.006135,
"change_amount": -0.06,
"amplitude": 0.010225,
"turnover_rate": 0.001281
}
}
]
}{
"op": "depth",
"data": [
{
"symbol": "600000.SH",
"region": "CN",
"timestamp": 1776754802000,
"bid_prices": [
9.72,
9.71,
9.7,
9.69,
9.68
],
"bid_volumes": [
3192,
3870,
26168,
5849,
5480
],
"ask_prices": [
9.73,
9.74,
9.75,
9.76,
9.77
],
"ask_volumes": [
74,
1602,
1148,
1209,
1109
]
}
]
}{
"op": "error",
"message": "no permission for channel: depth"
}api_key
type:httpApiKey
订阅频道
type:object
按频道和标的列表订阅,订阅成功后推送缓存快照
退订频道
type:object
按频道退订指定标的
频道订阅状态
type:object
subscribe / unsubscribe 操作后返回该频道的完整订阅列表
行情推送
type:object
实时行情数据,仅包含已订阅且有更新的标的
市场深度推送
type:object
五档盘口数据,仅包含已订阅 depth 频道且有更新的标的
错误消息
type:object
操作失败时返回的错误信息
⌘I
