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 数据预处理中的常见坑

⚠️ 我曾经踩过的坑:
  1. 时间戳重复:同一毫秒内有多笔成交,排序后顺序可能错乱。解决方案:加入「交易所内部序号」作为二级排序键。
  2. 价格跳空:夜盘收盘和日盘开盘之间价格可能跳空。做模式识别时要注意切分交易时段。
  3. 成交量异常:某些交易所的成交量是累计值,需要做差分才能得到单笔成交量。

嗯,数据结构这块就讲这么多。记住一句话:数据质量决定了模型的天花板。把五个字段理清楚,后面的模式识别才能站得住脚。