订单簿预测:利用深度学习预测短期价格走势
订单簿预测简介
订单簿(Order Book)是电子化交易市场中所有未成交挂单的实时列表,由买卖双方的限价指令组成。它记录每一档价格上的挂单量,是市场微观结构的核心。订单簿预测试图通过分析订单簿的形态与动态变化,预测短期价格走势,属于高频量化交易中的关键技术。
近年来,深度学习凭借其从高维、非结构化数据中自动提取特征的能力,在这一领域展现出显著优势。本教程将带你从零开始,构建一个基于深度学习的订单簿预测模型,即使你此前没有相关经验,也能逐步掌握完整的构建流程。
你需要准备什么
- Python 基础知识(熟悉 NumPy 和 Pandas)
- 基本机器学习概念(损失函数、优化器、过拟合等)
- 一台带 GPU 的计算机(推荐)或使用 Google Colab
- 订单簿快照数据集(教程中将使用模拟数据说明原理)
订单簿数据的结构与预处理
理解订单簿快照
典型的订单簿快照包含两层信息:买方挂单(Bid)和卖方挂单(Ask)。Bid 按价格从高到低排列,Ask 按价格从低到高排列。每一档通常包含两个字段:价格(Price)和数量(Size)。通常我们只使用前 N 档数据(例如前 10 档),因为更远档位对短期价格的影响较小。
一个 Level 2 订单簿快照的示例:
Bid Price 10: 100.50, Size: 200
Bid Price 9: 100.45, Size: 350
...
Bid Price 1: 99.80, Size: 500
Ask Price 1: 100.55, Size: 180
Ask Price 2: 100.60, Size: 220
...
Ask Price 10: 101.10, Size: 90
定义预测目标
短期价格走势预测通常转化为分类问题。常用的目标定义方式有两种:
- 中间价变动方向:计算快照的中间价
mid = (best_bid + best_ask) / 2,预测未来 k 个 tick(或固定时间间隔后)中间价是上涨、下跌还是持平。 - 价格跳动分类:预测未来一段时间内中间价的变化幅度是否超过某个阈值。
为了降低噪声并提高实用性,我们常采用 多级水平预测。例如,预测未来 10 个事件(tick)后的中间价变动方向,并定义上涨(标签 2)、持平(标签 1)、下跌(标签 0)。标签平滑(将变动极小的情况归为持平)能有效减少噪声。
特征工程
虽然深度学习能自动学习特征,但输入数据的表示方式仍然关键。将订单簿快照转换为模型输入时,通常采用以下特征:
基础特征(直接使用原始数据)
- 各档价格与中间价的差值(标准化或相对化)
- 各档挂单量
- 买卖不平衡指标:
(Bid_Size_1 - Ask_Size_1) / (Bid_Size_1 + Ask_Size_1) - 价差(Spread)
衍生特征
- 订单簿斜率:挂单量随价格的变化率
- 加权平均价格:按数量加权计算买卖双方的平均挂单价格
- 深度加权中间价:考虑前几档深度后的调整中间价
时序特征(使用多个连续快照)
深度学习模型擅长处理时序数据,因此我们将多个连续快照堆叠成一个样本。例如,使用过去 10 个快照(每个快照包含 40 维特征:20 个价格+20 个数量)来预测未来标签。
数据预处理流程
- 数据清洗:去除明显异常的快照(如价差为负、挂单量为零等)。
- 缺失值处理:如果某档不存在挂单,可将价格设为 0 或使用前值填充。
- 标准化:对价格相关特征减均值除标准差,或采用相对于中间价的比例,消除不同标的绝对价格差异。
- 样本构建:用滑动窗口生成
(历史序列, 未来标签)的监督学习样本。 - 类别平衡:订单簿数据往往极度不平衡(大量持平或微小波动)。可采用下采样、上采样或类别加权损失来应对。
# 示例:构建滑动窗口样本
def build_sequences(data, window_size, horizon):
X, y = [], []
for i in range(len(data) - window_size - horizon):
X.append(data[i : i + window_size]) # 历史窗口
# 计算未来 horizon 步后的中间价变动标签
future_mid = data[i + window_size + horizon, :]["mid_price"]
current_mid = data[i + window_size - 1, :]["mid_price"]
if future_mid > current_mid * 1.0001:
label = 2
elif future_mid < current_mid * 0.9999:
label = 0
else:
label = 1
y.append(label)
return np.array(X), np.array(y)
深度学习模型设计
处理订单簿时间序列的模型主流选项有:
- LSTM / GRU:经典循环网络,适合捕捉时序依赖。
- CNN(1D / 2D):一维卷积沿时间轴提取模式,二维卷积同时提取时间和特征交互。
- Transformer:利用自注意力机制建模长期依赖,近年来表现优异。
- 混合模型:CNN-LSTM、Transformer-CNN 等组合。
我们将重点介绍 CNN-LSTM 混合模型,因其在计算效率和预测性能间取得了良好平衡,适合初学者快速上手。
模型架构详解
模型输入形状为 (window_size, features),例如 (10 个快照, 40 维特征)。
- 输入层:接收形状为
(None, window_size, features)的张量。 - 1D 卷积块:两层 Conv1D 用于提取局部时间模式,例如卷积核大小 3,滤波器数量 64。使用 ReLU 激活,并添加 BatchNormalization 和 Dropout 防止过拟合。
- 池化层:MaxPooling1D 降低时间维度,保留显著特征。
- LSTM 层:堆叠 1~2 层 LSTM,单元数 64 或 128。设置
return_sequences=False输出最后时刻的隐藏状态,或者使用 Bidirectional 增强。 - 全连接层:Dense 层进行分类,输出层神经元数为类别数(3),激活函数 softmax。
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense, Dropout, BatchNormalization, Flatten
def build_cnn_lstm_model(window_size, features, num_classes=3):
model = Sequential([
Conv1D(filters=64, kernel_size=3, activation='relu', input_shape=(window_size, features)),
BatchNormalization(),
Conv1D(filters=64, kernel_size=3, activation='relu'),
BatchNormalization(),
MaxPooling1D(pool_size=2),
Dropout(0.3),
LSTM(128, return_sequences=False),
Dropout(0.3),
Dense(64, activation='relu'),
BatchNormalization(),
Dense(num_classes, activation='softmax')
])
return model
损失函数与优化器
多分类问题使用 分类交叉熵(Categorical Crossentropy)。如果类别不平衡,可以在损失函数中设置 class_weight 参数,或使用 Focal Loss 来聚焦困难样本。
优化器常用 Adam,因其收敛快且对超参数不太敏感。学习率初始可设为 0.001,配合学习率衰减。
评估指标
由于预测任务通常面临类别不平衡,单纯使用准确率会掩盖模型真实表现。应重点关注:
- F1 分数(宏平均或加权平均)
- 混淆矩阵:观察各方向的预测正确率和误差分布
- 收益相关指标:如果模型用于交易,可回测计算夏普比率、最大回撤等,但本教程侧重分类性能本身。
模型训练与调优
训练配置
- 划分训练集、验证集、测试集(按时间顺序,避免未来信息泄漏)。
- 批次大小:32 或 64,根据 GPU 内存调整。
- 早停法(EarlyStopping):监控验证损失,耐心值设为 10~20 个 epoch。
- 模型检查点(ModelCheckpoint):保存验证损失最低的模型。
- 学习率衰减:当验证损失停滞时降低学习率。
应对过拟合的技巧
- Dropout:在卷积层和 LSTM 层后设置 0.3~0.5。
- L2 正则化:对权重施加惩罚。
- 数据增强:对订单簿快照进行微小扰动(如加噪声、随机时间偏移),但需谨慎以免破坏结构。
- 减小模型容量:先从较小网络开始,随数据量增加逐步扩大。
超参数搜索
手动调参或使用 Keras Tuner / Optuna 可优化以下参数:
- 窗口大小(window_size)
- 卷积核大小和滤波器数量
- LSTM 单元数
- 学习率及衰减策略
- Dropout 比率
初步实验可固定窗口大小 10~20,重点调查卷积和 LSTM 容量。
从预测到交易信号
模型输出 softmax 概率,代表各方向置信度。转化为交易信号时需设置阈值,避免在低置信度时频繁交易。
示例策略:
- 如果上涨概率 > 0.6 且下跌概率 < 0.2,则发出买入信号。
- 如果下跌概率 > 0.6 且上涨概率 < 0.2,则发出卖出信号。
- 其他情况保持不动或平仓。
此外,应结合市场微观结构约束(手续费、滑点、最小变动价位)进行模拟,才能评估真实盈利能力。
常见问题与陷阱
1. 数据窥探(Look-ahead Bias)
确保构建样本时,标签严格在未来信息不可知的时间点定义。窗口右边界不能接触未来数据。
2. 幸存者偏差
使用的历史订单簿数据可能只包含存活下来的标的,忽略退市或合并的资产,导致训练信号过于乐观。
3. 类别不平衡
大部分时刻价格并无明显变动,如果模型总是预测“持平”,准确率可能很高但毫无用处。必须用加权损失或合适的评估指标纠正。
4. 市场状态变化
金融市场非平稳,模型需要定期再训练。可设计在线学习机制,每天或每周用新数据微调模型。
5. 实盘延迟
订单簿高频变化,从捕获快照到模型推理再到下单,中间延迟可能导致信号失效。模型应尽量轻量,特征计算和推理需在微秒级完成。
拓展:先进方法简介
掌握基础方法后,可进一步探索:
- DeepLOB:专门为订单簿设计的深度架构,结合卷积模块提取局部价格模式,再通过 Inception 模块整合多尺度信息,最后用 LSTM 处理时序。
- Transformer 方案:将快照序列通过位置编码输入 Transformer 编码器,利用注意力权重捕捉买卖压力变化。
- 生成对抗模拟:使用 GAN 生成接近真实的订单簿数据,用于扩充训练集或压力测试。
- 强化学习:把订单簿特征作为状态,直接输出交易动作,由累计收益驱动学习。
- 多维度融合:加入成交数据(交易量和时间)、新闻情感等其他模态,提升信号稳健性。
小结与下一步
通过本教程,你已经了解了订单簿预测的核心概念、数据处理方法、CNN-LSTM 模型构建及训练技巧。动手实践是掌握该技术的最佳途径。
建议的学习路径:
- 先获取仿真订单簿数据(如 Lobster 数据集、Bitcoin 订单簿公开数据等)。
- 完整实现数据预处理、模型搭建、训练和评估流程。
- 调整网络结构和超参数,记录实验日志。
- 在回测框架中尝试简单的交易规则,观察实际盈亏。
继续深入,你将能够构建更复杂的模型,并在真实的量化交易环境中部署。祝你在订单簿预测的探索中取得突破!