市场数据模型:Tick数据、Order Book数据、K线数据
做量化交易,尤其是高频策略,第一道坎就是数据。
我见过太多人,策略逻辑写得天花乱坠,结果一跑回测就崩。为什么?数据模型没搞对。说白了,你连市场长什么样都没搞清楚,怎么赚钱?
今天咱们就把这块硬骨头啃下来。我会把Tick、Order Book、K线这三种核心数据模型,掰开揉碎了讲清楚。
1. Tick数据:市场的原子单位
Tick数据是什么?就是每一笔成交的原始记录。它是最细粒度的数据,没有之一。
我个人习惯把Tick数据叫做「市场的呼吸」。每一笔成交,都是市场的一次呼吸。高频策略吃的就是这口「气」。
1.1 Tick数据字段定义
一个标准的Tick数据,至少包含以下字段:
| 字段名 | 类型 | 说明 |
|---|---|---|
| symbol | string | 合约代码,比如 "BTCUSDT" |
| timestamp | int64 | 成交时间戳,精确到毫秒或微秒 |
| price | float64 | 成交价格 |
| volume | float64 | 成交量(币的数量) |
| side | int8 | 成交方向:1=主动买,-1=主动卖,0=未知 |
| trade_id | int64 | 交易所唯一成交ID |
1.2 Tick数据标准化
不同交易所,字段名不一样,格式也不一样。比如币安叫 "t",OKX叫 "instId"。怎么办?标准化。
# 这是我常用的Tick标准化函数
def normalize_tick(raw_tick, exchange):
"""
将不同交易所的Tick数据统一为标准格式
"""
if exchange == 'binance':
return {
'symbol': raw_tick['s'],
'timestamp': int(raw_tick['T']),
'price': float(raw_tick['p']),
'volume': float(raw_tick['q']),
'side': 1 if raw_tick['m'] else -1,
'trade_id': int(raw_tick['t'])
}
elif exchange == 'okx':
return {
'symbol': raw_tick['instId'],
'timestamp': int(raw_tick['ts']),
'price': float(raw_tick['px']),
'volume': float(raw_tick['sz']),
'side': 1 if raw_tick['side'] == 'buy' else -1,
'trade_id': int(raw_tick['tradeId'])
}
# 其他交易所类似处理
你看,标准化之后,你的策略代码就不用关心底层数据源了。这是基本功。
2. Order Book数据:市场的深度与博弈
Order Book,也就是订单簿。它告诉你:现在有多少人在买,多少人在卖,价格挂在哪。
我当年做做市商策略时,Order Book就是我的「眼睛」。没有它,你根本不知道市场的真实流动性在哪。
2.1 Order Book数据结构
一个完整的Order Book快照,包含以下部分:
- bids:买单列表,按价格从高到低排序
- asks:卖单列表,按价格从低到高排序
- timestamp:快照时间
- sequence:序列号,用于检测数据是否连续
每个订单条目包含:价格、数量、订单数量(可选)。
# Order Book快照示例
order_book_snapshot = {
'symbol': 'BTCUSDT',
'timestamp': 1625000000000,
'bids': [
[35000.0, 1.5], # 价格35000,数量1.5个BTC
[34999.5, 2.0],
[34999.0, 0.8]
],
'asks': [
[35001.0, 1.2],
[35001.5, 3.0],
[35002.0, 0.5]
],
'sequence': 123456789
}
2.2 增量更新 vs 全量快照
这里有个关键点:Order Book是实时变化的。每次有人下单、撤单,订单簿都会变。
交易所通常提供两种数据:
- 全量快照:每隔一段时间(比如100ms)给你整个订单簿
- 增量更新:每次变化时,只告诉你变了什么
2.3 Order Book的深度指标
从Order Book里,我们可以算出很多有用的指标:
| 指标 | 计算方式 | 用途 |
|---|---|---|
| 买卖价差 | ask[0].price - bid[0].price | 衡量市场流动性 |
| 深度加权价格 | 按数量加权平均 | 判断真实成交价格 |
| 订单不平衡度 | (bid_vol - ask_vol) / (bid_vol + ask_vol) | 预测短期价格方向 |
| 价格冲击成本 | 吃掉N层订单需要的成本 | 评估大单执行成本 |
3. K线数据:时间维度的压缩
K线,也叫OHLCV。它是把一段时间内的交易数据,压缩成四个价格:开盘、最高、最低、收盘,外加成交量。
说实话,K线是给中低频策略用的。高频策略很少直接用K线,因为信息损失太大了。但做回测时,K线可以用来做快速验证。
3.1 K线字段定义
| 字段 | 说明 |
|---|---|
| open | 开盘价 |
| high | 最高价 |
| low | 最低价 |
| close | 收盘价 |
| volume | 成交量 |
| timestamp | K线开始时间 |
3.2 从Tick合成K线
有时候你只有Tick数据,但需要K线做分析。那就自己合成。
def ticks_to_kline(ticks, interval_ms=60000):
"""
将Tick数据合成为K线
interval_ms: K线周期,默认1分钟
"""
klines = []
current_kline = None
for tick in ticks:
# 计算当前Tick属于哪个K线周期
kline_time = (tick['timestamp'] // interval_ms) * interval_ms
if current_kline is None or current_kline['timestamp'] != kline_time:
# 新K线开始
if current_kline is not None:
klines.append(current_kline)
current_kline = {
'timestamp': kline_time,
'open': tick['price'],
'high': tick['price'],
'low': tick['price'],
'close': tick['price'],
'volume': tick['volume']
}
else:
# 更新当前K线
current_kline['high'] = max(current_kline['high'], tick['price'])
current_kline['low'] = min(current_kline['low'], tick['price'])
current_kline['close'] = tick['price']
current_kline['volume'] += tick['volume']
return klines
4. 数据标准化:统一战场
数据标准化,说白了就是让所有数据「说同一种语言」。
我做过一个项目,同时接入5个交易所的数据。每个交易所的字段名、时间格式、价格精度都不一样。如果不标准化,你的策略代码会变成一团乱麻。
4.1 标准化的几个维度
- 时间标准化:统一为UTC时间戳,精确到毫秒
- 价格标准化:统一为float64,注意精度问题
- 数量标准化:统一为float64,注意小数位数
- 方向标准化:买卖方向用+1/-1表示
- 缺失值处理:用NaN或-1填充,不要用0
4.2 数据质量检查
数据标准化之后,一定要做质量检查。我吃过这个亏——数据里有重复的Tick,导致回测结果虚高。
def check_data_quality(ticks):
"""
检查Tick数据质量
"""
issues = []
# 检查时间戳是否递增
for i in range(1, len(ticks)):
if ticks[i]['timestamp'] <= ticks[i-1]['timestamp']:
issues.append(f"时间戳异常: index {i}")
# 检查价格是否合理
for tick in ticks:
if tick['price'] <= 0:
issues.append(f"价格异常: {tick}")
# 检查是否有重复trade_id
trade_ids = [t['trade_id'] for t in ticks]
if len(trade_ids) != len(set(trade_ids)):
issues.append("存在重复的trade_id")
return issues
5. 知识体系总览
下面这张图,是我自己总结的市场数据模型知识体系。你看一眼,就能明白今天讲的所有内容是怎么串起来的。
这张图把今天的内容都串起来了。你看,Tick是源头,Order Book是深度,K线是压缩。而标准化,是贯穿始终的「通用语言」。
好了,市场数据模型这块,咱们就聊到这。记住一句话:数据模型是回测系统的地基。地基不稳,楼盖得再高也得塌。