4、Tick级数据与时间序列:Tick数据结构(时间、价格、成交量)、逐笔成交与逐笔委托、Level 1/Level 2/Level 3数据区别、数据清洗与对齐
聊到美股微观结构,Tick级数据是绕不开的硬骨头。我刚开始接触这个领域时,以为Tick数据就是简单的「时间、价格、成交量」三列。后来在实盘回测中被坑过几次,才明白这里面门道有多深。
说白了,Tick数据是市场最原始的呼吸记录。每一笔成交、每一条委托单,都是市场参与者的真实投票。你想想看,如果连这些原始数据都处理不好,后面那些高阶策略根本无从谈起。
4.1 Tick数据结构:时间、价格、成交量
先看最基础的Tick数据结构。美股交易所通常以微秒甚至纳秒级精度记录数据。我见过不少新手直接把Tick数据当1分钟K线用,这其实浪费了太多信息。
一个标准的逐笔成交Tick,通常包含以下字段:
| 字段 | 说明 | 示例 |
|---|---|---|
| Timestamp | 交易所时间戳(纳秒级) | 2024-01-15 09:30:00.123456789 |
| Price | 成交价格(精确到美分) | 185.23 |
| Volume | 成交量(股数) | 100 |
| Trade Condition | 成交条件标记 | @(常规)、F(非显示) |
| Exchange Code | 交易所代码 | N(NYSE)、Q(NASDAQ) |
这里有个坑——不同数据商的时间戳精度不一样。我遇到过一家数据商给的是毫秒级,另一家是微秒级。对齐时如果不做精度统一,回测结果会差很多。
核心要点:Tick数据的时间戳精度直接影响订单簿重建的准确性。我个人习惯统一转为纳秒级处理,避免精度丢失。
4.2 逐笔成交与逐笔委托
很多人分不清逐笔成交(Trade)和逐笔委托(Quote/Order)的区别。我简单解释一下:
- 逐笔成交:记录每一笔实际发生的交易。谁买了、谁卖了、多少钱、多少股。
- 逐笔委托:记录每一笔订单的挂单、撤单、修改行为。包括限价单、市价单、冰山订单等。
为什么要区分?因为成交是「果」,委托是「因」。你想分析主力动向,只看成交数据是不够的。我曾经在分析某只中概股时,发现成交数据显示大单买入,但委托数据却显示有人在偷偷撤单。嗯,这就是典型的「挂单诱多」手法。
逐笔委托的数据结构更复杂一些:
// 逐笔委托示例(JSON格式)
{
"timestamp": "2024-01-15 09:30:01.123456",
"order_id": "ORD123456789",
"side": "BUY",
"price": 185.20,
"size": 500,
"order_type": "LIMIT",
"action": "ADD", // ADD, CANCEL, MODIFY
"exchange": "NASDAQ"
}
实战技巧:如果你只有逐笔成交数据,可以尝试用「成交量分布」反推委托行为。但精度肯定不如直接拿逐笔委托数据。我建议有条件的话,两者都拿。
4.3 Level 1 / Level 2 / Level 3 数据区别
这个知识点是很多人的盲区。我直接画个图,一目了然:
简单总结一下:
- Level 1:就是你在券商APP上看到的那种。只有最佳买卖价和最新成交价。说实话,做量化交易基本不够用。
- Level 2:能看到多档盘口和逐笔成交。很多个人交易者觉得这就够了。但我想说,如果你只做趋势跟踪,Level 2确实够用。但要做高频或统计套利,还差得远。
- Level 3:全量委托数据。能看到每一笔挂单、撤单、修改。这才是真正意义上的「市场微观结构」数据。我曾经用Level 3数据重建过某只股票的完整订单簿,那种掌控感是Level 2给不了的。
注意:Level 3数据不是所有券商都提供的。而且数据量极大,一只活跃股票一天可能产生上亿条委托记录。存储和计算成本都不低。我建议先评估你的策略需求,再决定是否上Level 3。
4.4 数据清洗与对齐
这部分是我踩坑最多的。数据清洗听起来简单,做起来全是细节。
常见问题一:时间戳对齐
不同交易所的时间戳基准不一样。NYSE用东部时间,NASDAQ用UTC。我遇到过最离谱的一次,某数据商把时间戳混用了,导致回测结果完全失真。
我的处理流程:
# 伪代码:时间戳统一处理
def align_timestamps(df):
# 1. 统一转为UTC
df['timestamp_utc'] = pd.to_datetime(df['timestamp'], utc=True)
# 2. 对齐到微秒级
df['timestamp_aligned'] = df['timestamp_utc'].dt.floor('us')
# 3. 检查是否有重复时间戳
dup_mask = df['timestamp_aligned'].duplicated(keep=False)
if dup_mask.any():
# 微调:按顺序加1纳秒
df.loc[dup_mask, 'timestamp_aligned'] += pd.Timedelta(nanoseconds=1)
return df
常见问题二:异常值处理
Tick数据里经常出现一些「幽灵数据」。比如价格突然跳到0,或者成交量是负数。我曾经在分析某只低价股时,发现一笔成交价是0.01美元,明显是数据错误。
我的清洗规则:
- 价格必须在合理范围内(比如当日涨跌幅限制内)
- 成交量必须大于0
- 时间戳不能是未来时间
- 交易所代码必须合法
常见问题三:数据对齐
当你同时有成交数据和委托数据时,对齐是个大问题。成交数据可能比委托数据晚几微秒到达。如果你直接按时间戳合并,会得到错误的结果。
我建议的做法是:
- 先按时间戳排序
- 用「最近邻」方式匹配成交和委托
- 设置一个时间窗口(比如100微秒),窗口内的数据视为同一事件
个人经验:数据清洗这一步,我建议至少花30%的项目时间。别急着跑策略,先把数据搞干净。我曾经因为一个时间戳对齐问题,浪费了整整两周的算力。嗯,从那以后我再也不敢跳过数据清洗了。
最后说一句,Tick级数据是微观结构分析的基石。你花在数据清洗上的每一分钟,都会在后续的策略开发中得到回报。别嫌麻烦,这是必经之路。
公众号:蓝海资料掘金营,微信deep3321