2. 事件序列数据结构:时间戳、价格、成交量、买卖方向、订单类型
好,咱们直接进入正题。
做事件序列模式识别,第一步不是写模型,而是搞清楚数据长什么样。说白了,你得知道你的「原材料」是什么。
我见过不少新手,一上来就调包跑LSTM,结果数据字段都没对齐,跑出来的结果自然是一团糟。嗯,这里咱们先把地基打牢。
2.1 一条完整的事件记录长什么样?
在量化交易里,一个「事件」不是K线,而是每一笔成交或每一笔订单的切片。我个人习惯把它看作一个五元组:
Event = (Timestamp, Price, Volume, Side, OrderType)
这五个字段,缺一不可。你想想看,如果少了买卖方向,你怎么知道这笔交易是主动买还是主动卖?少了订单类型,你怎么区分是市价单扫货还是限价单挂在那等人吃?
下面这张图,是我自己画的事件序列数据结构图,帮你快速建立整体认知:
2.2 逐个拆解五个字段
2.2.1 时间戳(Timestamp)
时间戳是事件序列的「坐标轴」。没有它,事件就排不出先后顺序,模式识别也就无从谈起。
这里有个坑,我曾经踩过——不同交易所的时间精度不一样。有的精确到毫秒,有的精确到微秒,甚至纳秒。如果你把毫秒级和微秒级的数据混在一起排序,结果会非常诡异。
举个例子,一个典型的时间戳字段在Python里长这样:
# 推荐使用整数纳秒
timestamp_ns = 1698765432123456789 # 2023-10-31 12:34:52.123456789
# 不推荐使用字符串
timestamp_str = "2023-10-31 12:34:52.123456" # 排序慢,易出错
2.2.2 价格(Price)
价格是交易的核心。但要注意,价格字段不只是数字那么简单。
在实际行情中,价格有「成交价」和「报价」之分。成交价是实际撮合的价格,报价是买卖盘口上的挂单价格。做事件序列时,我们通常用成交价,因为它反映了真实的资金博弈。
| 价格类型 | 含义 | 使用场景 |
|---|---|---|
| 成交价(Trade Price) | 实际撮合的价格 | 事件序列、策略信号 |
| 买一价(Bid Price) | 最高买入报价 | 盘口分析、流动性评估 |
| 卖一价(Ask Price) | 最低卖出报价 | 盘口分析、价差计算 |
2.2.3 成交量(Volume)
成交量代表「力度」。同样的价格变动,配合不同的成交量,含义天差地别。
举个例子:价格涨了1%,如果成交量只有平时的十分之一,那可能是虚涨;如果成交量是平时的十倍,那就是真金白银在买。
这里要注意一个细节——成交量的单位。有的交易所按「股」算,有的按「手」算,还有的按「张」算。做跨市场分析时,一定要统一单位。
# 统一转为「基础单位」
volume_in_shares = volume_in_lots * lot_size # 手数 × 每手股数
2.2.4 买卖方向(Side)
买卖方向是事件序列里最容易被忽视、但最重要的字段之一。
它告诉你这笔交易是谁主动发起的。主动买(Buy)意味着买方更急切,主动卖(Sell)意味着卖方更急切。这个信息在模式识别里非常关键。
我一般用枚举值来表示:
from enum import Enum
class Side(Enum):
BUY = 1 # 主动买
SELL = -1 # 主动卖
# 有些交易所还有 NEUTRAL(中性),但很少见
2.2.5 订单类型(OrderType)
订单类型告诉你这笔交易是怎么发生的。常见的类型有:
- 市价单(Market Order):立即成交,不关心价格。代表「急迫」。
- 限价单(Limit Order):指定价格,等待成交。代表「耐心」。
- 撤单(Cancel):取消之前挂的单。代表「变卦」。
- 冰山订单(Iceberg Order):只显示部分数量。代表「隐藏意图」。
我曾经在分析某只股票的闪崩事件时发现,大量市价卖单在短时间内涌入,而买单全是限价单且价格挂得很低。这种「订单类型不对称」就是典型的闪崩前兆。
2.3 完整的数据结构示例
好了,把五个字段拼起来,一个完整的事件记录长这样:
{
"timestamp": 1698765432123456789, # 纳秒级时间戳
"price": 15250, # 价格,单位:分
"volume": 1000, # 成交量,单位:股
"side": 1, # 1=主动买, -1=主动卖
"order_type": "market" # 订单类型:market/limit/cancel
}
在实际项目中,我通常会用 pandas.DataFrame 来存储这些数据,列名直接对应五个字段:
import pandas as pd
# 假设 data 是上面格式的字典列表
df = pd.DataFrame(data)
df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ns')
# 排序,确保时间顺序
df = df.sort_values('timestamp').reset_index(drop=True)
2.4 数据预处理中的常见坑
- 时间戳重复:同一毫秒内有多笔成交,排序后顺序可能错乱。解决方案:加入「交易所内部序号」作为二级排序键。
- 价格跳空:夜盘收盘和日盘开盘之间价格可能跳空。做模式识别时要注意切分交易时段。
- 成交量异常:某些交易所的成交量是累计值,需要做差分才能得到单笔成交量。
嗯,数据结构这块就讲这么多。记住一句话:数据质量决定了模型的天花板。把五个字段理清楚,后面的模式识别才能站得住脚。