数据源与获取:沪深交易所Level-2行情接口、Tick级数据订阅、历史逐笔委托数据回放

做逐笔委托流分析,第一步就是搞定数据。没有数据,再牛的策略也是空中楼阁。

我刚开始接触Level-2行情时,其实挺懵的。市面上各种接口、各种协议,到底该选哪个?数据到了手里,又该怎么用?今天咱们就把这事彻底聊透。

Level-2行情接口:到底比Level-1强在哪?

普通投资者用的Level-1行情,是3秒快照。说白了,你看到的盘口是3秒前的样子。做短线交易,这3秒的延迟足够让你吃大亏。

Level-2行情就不一样了。它提供的是逐笔成交和逐笔委托的原始数据流。我个人的习惯是,只要做高频相关的策略,必须上Level-2。

核心差异对比:
对比项 Level-1行情 Level-2行情
刷新频率 3秒一次快照 实时逐笔推送
委托队列 仅显示前5档 显示前50档(深交所)或全量(上交所)
逐笔成交 有,包含每笔成交的买卖方向
逐笔委托 有,能看到每一笔挂单的撤单、成交
数据用途 趋势判断 主力资金追踪、订单簿重构

你想想看,如果你能看到每一笔委托的来龙去脉,是不是就能判断出主力是在吸筹还是在出货?这就是Level-2的价值所在。

Tick级数据订阅:实时流的接入方式

实时数据订阅,通常有两种方式:WebSocket和TCP直连。

WebSocket方式:适合个人开发者。门槛低,用Python的websocket库就能搞定。我早期做回测系统时,就是用WebSocket接的某券商的模拟盘。

TCP直连方式:适合机构。延迟更低,但需要自己维护心跳、重连、数据校验。嗯,这里要注意,TCP直连的协议通常是二进制格式,你得自己解析。

我的建议:刚开始做研究,用WebSocket就够了。等策略成熟了,再考虑上TCP直连。别一上来就搞复杂的,容易劝退自己。

下面是一个简单的WebSocket订阅示例,订阅某只股票的逐笔委托流:

import websocket
import json

def on_message(ws, message):
    data = json.loads(message)
    # 解析逐笔委托数据
    if data['type'] == 'tick_order':
        print(f"时间: {data['time']}, 价格: {data['price']}, 数量: {data['volume']}, 方向: {data['direction']}")

def on_error(ws, error):
    print(f"连接异常: {error}")

def on_close(ws, close_status_code, close_msg):
    print("连接已关闭")

def on_open(ws):
    # 订阅股票代码
    subscribe_msg = {
        "action": "subscribe",
        "symbol": "600519",
        "channel": "tick_order"
    }
    ws.send(json.dumps(subscribe_msg))

if __name__ == "__main__":
    ws = websocket.WebSocketApp("wss://your-broker-api.com/level2",
                                on_open=on_open,
                                on_message=on_message,
                                on_error=on_error,
                                on_close=on_close)
    ws.run_forever()

这段代码看着简单,但实际跑起来坑不少。我曾经遇到过WebSocket莫名其妙断开,结果漏掉了关键数据,导致策略信号出错。后来我加了个心跳检测和自动重连机制,才算稳定下来。

历史逐笔委托数据回放:模拟真实战场

实时数据用来做交易,历史数据用来做回测。两者缺一不可。

历史逐笔委托数据,一般以CSV或Parquet格式存储。我推荐用Parquet,压缩率高,读取速度快。尤其是处理上亿条数据时,CSV能把你等哭。

避坑指南:我曾经用CSV存了一个月的逐笔数据,文件大小超过10GB。每次回测加载数据要花5分钟。换成Parquet后,加载时间缩短到30秒。数据格式的选择,直接影响你的开发效率。

数据回放的核心逻辑,就是按时间顺序逐笔推送数据,模拟真实的交易环境。下面是一个简单的回放框架:

import pandas as pd
import time

class TickReplayer:
    def __init__(self, data_path):
        self.data = pd.read_parquet(data_path)
        self.data = self.data.sort_values('time')  # 按时间排序
        self.index = 0
    
    def replay(self, speed=1.0):
        """回放逐笔委托数据"""
        while self.index < len(self.data):
            tick = self.data.iloc[self.index]
            # 模拟真实时间间隔
            if self.index > 0:
                prev_time = self.data.iloc[self.index - 1]['time']
                time_diff = (tick['time'] - prev_time) / speed
                time.sleep(time_diff)
            
            # 处理当前tick
            self.process_tick(tick)
            self.index += 1
    
    def process_tick(self, tick):
        """处理单笔委托数据"""
        print(f"回放: {tick['time']} | 价格: {tick['price']} | 数量: {tick['volume']} | 方向: {tick['direction']}")

# 使用示例
replayer = TickReplayer('data/2024_01_tick.parquet')
replayer.replay(speed=10.0)  # 10倍速回放

这个回放器虽然简陋,但核心思想都在了。实际项目中,你还需要考虑数据校验、异常处理、性能优化等问题。

数据获取的整体架构

说了这么多,咱们用一张图来总结一下整个数据获取的流程:

逐笔委托数据获取架构图 沪深交易所 Level-2行情源 接入方式 WebSocket / TCP直连 数据解析 二进制/JSON解码 数据存储 Parquet / CSV / 数据库 数据应用 实时交易 / 历史回放 回放引擎 TickReplayer 数据流方向:交易所 → 接入 → 解析 → 存储 → 应用/回放

这张图把整个数据获取链路串起来了。从交易所源头,到接入方式,再到数据解析、存储,最后到实时交易和历史回放。每一步都有坑,每一步也都有优化空间。

个人经验:我建议你先把历史回放这块做扎实。因为回放环境可以反复调试,不会亏真金白银。等回放策略稳定了,再切换到实时数据。这个顺序,能帮你省下不少学费。

好了,数据源和获取这块就聊到这。记住一句话:数据质量决定策略上限。花时间把数据链路搞通,后面的分析才能事半功倍。

专注资料整理