核心问题:当我使用 WebSocket 订阅实时行情时,发现部分停牌股票仍在持续推送数据,其价格维持不变、成交量为零。如何在代码中高效识别并过滤这些股票?不同数据接口的差异又该如何处理?
最佳实践方案
这类问题在实时数据流处理中相当典型。下面从需求痛点、数据特征到最终落地方案逐一拆解,帮助您更清晰地理解。
需求与痛点分析
核心需求非常明确:区分可正常交易的活跃标的与暂停交易的停牌标的。若过滤不到位,技术指标会被污染,前端展示容易产生误导。早期一些方案仅靠价格变化来判断,但流动性极低的股票有时价格长时间不动,导致误判。更麻烦的是,接口持续推送无用数据,白白消耗连接资源和计算性能。
数据支撑:停牌行为的常见模式
根据主流行情接口的实际表现,停牌股票的推送行为大致可归纳为以下几种模式:
| 模式 | 详细描述 | 判定难度 |
|---|---|---|
| 价格冻结 | 最新价不再发生变化 | 低(但不可单独依赖) |
| 成交量归零 | 累计成交量停止增长 | 中 |
| 状态字段 | 直接提供 suspend 等关键标识 | 低,最可靠 |
| 时间戳更新 | 推送时间持续跳动,但无实际交易 | 无意义 |
因此,优先使用状态字段是最可靠的做法。若接口未提供状态字段,则可以采用成交量与价格静默时长组合判断。
实战方案:分层处理与代码实现
推荐将处理逻辑划分为三个层次:数据接收层过滤、业务计算层剔除、连接管理层取消订阅。
若您的接口包含 suspend 字段(例如 AllTick),可参考以下实现:
import websocket
import json
def on_message(ws, message):
data = json.loads(message)
for tick in data.get("ticks", []):
if tick.get("suspend"): # 检测停牌状态
print(f"{tick['symbol']} 当前处于停牌状态")
else:
print(f"{tick['symbol']} 最新价格: {tick['last_price']}")
ws = websocket.WebSocketApp("wss://api.alltick.co/stock", on_message=on_message)
ws.run_forever()随后,在计算模块中直接跳过停牌标的,并在检测到停牌时将该标的从订阅列表中移除,从而降低整体负载。
不同接口的差异与针对性应对
不同数据接口的行为差异较大:有的停牌后立即停止推送;有的通过状态码变化通知;有的仅停止盘口数据,但价格仍然照常推送。通常的应对策略是:在上线前做一次全量数据记录,根据实际行为将股票划分为三类:活跃股票、停牌股票、新上市/退市股票。然后为每类编写独立的管理逻辑。停牌处理本质上属于数据清洗与状态同步的一部分,只要统一了分类和过滤规则,系统的稳定性便会显著提升。
