16. 深度学习应用:LSTM时序预测基差,端到端交易信号生成。
基差交易做到最后,你会发现一个核心问题:基差到底会往哪个方向走?
传统的时间序列模型,像ARIMA、GARCH,我用了好多年。坦白说,在震荡行情里它们还行。但一旦遇到市场结构突变,比如政策干预、交割月临近,这些模型就很容易“掉链子”。
后来我开始尝试LSTM。为什么选它?因为LSTM能记住长期依赖关系。你想想看,基差的走势往往不是孤立的,它受近月合约、远月合约、库存、资金情绪等多重因素影响。LSTM的门控机制,说白了就是能决定“哪些历史信息该记住,哪些该忘掉”。
这一章,我就带你完整走一遍:如何用LSTM预测基差,并直接生成交易信号。
16.1 为什么是LSTM?不是Transformer?
你可能要问:现在Transformer这么火,为什么不用?
我个人习惯是:先看数据量。基差数据通常是日频或小时频,样本量几千到几万条。对于这种规模,LSTM的训练稳定性和可解释性都优于Transformer。我在项目中遇到过用Transformer做基差预测,结果在小样本下过拟合严重,调参调到头秃。
另外,LSTM的时序因果性更自然。它从左到右读数据,不会像Transformer那样需要位置编码。对于金融时序这种“顺序就是一切”的数据,LSTM的归纳偏置更合适。
核心结论: 数据量 < 10万条,优先选LSTM;数据量 > 100万条,可以考虑Transformer。
16.2 数据准备:从Tick到监督学习样本
做LSTM之前,数据必须整理成“监督学习”格式。说白了,就是用过去N天的特征,预测未来M天的基差。
我的标准流程:
- 计算基差: 基差 = 近月合约价格 - 远月合约价格。注意,要剔除交割日附近的数据,避免换月跳空。
- 特征工程: 除了基差本身,我还会加入:持仓量变化、成交量比率、波动率、以及跨期价差的一阶差分。
- 归一化: LSTM对输入尺度敏感。我习惯用MinMaxScaler,把每个特征缩放到[0,1]区间。
- 构建序列: 设定时间步长(lookback)为20天。也就是说,用过去20天的数据预测第21天的基差。
import numpy as np
import pandas as pd
from sklearn.preprocessing import MinMaxScaler
def create_sequences(data, lookback=20):
X, y = [], []
for i in range(lookback, len(data)):
X.append(data[i-lookback:i])
y.append(data[i, 0]) # 假设第一列是基差
return np.array(X), np.array(y)
# 假设df已经包含基差和其他特征
features = ['basis', 'oi_change', 'volume_ratio', 'volatility']
scaler = MinMaxScaler()
scaled_data = scaler.fit_transform(df[features])
X, y = create_sequences(scaled_data, lookback=20)
print(f"X shape: {X.shape}, y shape: {y.shape}")
# 输出: X shape: (980, 20, 4), y shape: (980,)
避坑指南: 我曾经在构建序列时忘了shuffle数据,导致训练集和测试集时间重叠。结果回测曲线漂亮得不像话,实盘直接打脸。记住:时序数据绝对不能随机打乱,必须按时间顺序切分。
16.3 模型架构:简单但有效
很多人一上来就堆层数,觉得层数越多越厉害。其实不然。对于基差预测这种任务,两层LSTM + 一层全连接通常就够了。
我的默认配置:
- 第一层LSTM:64个单元,return_sequences=True
- 第二层LSTM:32个单元,return_sequences=False
- Dropout层:0.2,防止过拟合
- 全连接层:16个神经元,ReLU激活
- 输出层:1个神经元,线性激活(回归任务)
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense, Dropout
model = Sequential([
LSTM(64, return_sequences=True, input_shape=(20, 4)),
Dropout(0.2),
LSTM(32, return_sequences=False),
Dropout(0.2),
Dense(16, activation='relu'),
Dense(1)
])
model.compile(optimizer='adam', loss='mse', metrics=['mae'])
model.summary()
嗯,这里要注意:return_sequences这个参数。第一层设为True,是因为我们要把完整的序列输出给第二层LSTM。最后一层LSTM设为False,只输出最后一个时间步的结果。
16.4 训练策略:早停与学习率衰减
训练LSTM时,我最怕的就是过拟合。基差数据本身信噪比低,模型很容易学到噪声。
我的做法:
- 早停(EarlyStopping): 监控验证集loss,连续10个epoch不下降就停止。
- 学习率衰减(ReduceLROnPlateau): 当验证集loss停滞时,学习率乘以0.5。
- 验证集比例: 用最后20%的数据做验证,保证时间顺序。
from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau
# 按时间顺序切分
split_idx = int(len(X) * 0.8)
X_train, X_val = X[:split_idx], X[split_idx:]
y_train, y_val = y[:split_idx], y[split_idx:]
callbacks = [
EarlyStopping(monitor='val_loss', patience=10, restore_best_weights=True),
ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=5)
]
history = model.fit(
X_train, y_train,
validation_data=(X_val, y_val),
epochs=100,
batch_size=32,
callbacks=callbacks,
verbose=1
)
注意: 不要用默认的batch_size=32就万事大吉。我建议根据数据量调整:数据量小(<5000条)用batch_size=16;数据量大用32或64。batch_size太大容易陷入局部最优。
16.5 从预测到交易信号:端到端生成
模型预测出基差后,怎么变成交易信号?这里有个关键点:不要直接拿预测值开仓。
我的做法是:
- 预测未来5天的基差均值
- 与当前基差比较,计算预期变化幅度
- 设定阈值:变化幅度 > 2倍历史标准差,才生成信号
说白了,就是过滤掉小波动,只抓大趋势。
def generate_signals(predictions, current_basis, threshold_std=2):
"""
predictions: 模型预测的未来5天基差
current_basis: 当前基差
"""
expected_change = np.mean(predictions) - current_basis
std_basis = np.std(predictions) # 预测值的标准差
if expected_change > threshold_std * std_basis:
return 1 # 做多基差(买入近月,卖出远月)
elif expected_change < -threshold_std * std_basis:
return -1 # 做空基差(卖出近月,买入远月)
else:
return 0 # 无信号
# 假设model已经训练好
last_20_days = scaled_data[-20:].reshape(1, 20, 4)
pred_future = []
for _ in range(5):
pred = model.predict(last_20_days, verbose=0)
pred_future.append(pred[0, 0])
# 滚动预测:将新预测加入序列,移除最早的数据
new_row = np.append(last_20_days[0, 1:], [[pred[0,0], 0, 0, 0]], axis=0)
last_20_days = new_row.reshape(1, 20, 4)
signal = generate_signals(pred_future, current_basis)
print(f"交易信号: {signal}")
16.6 回测与评估:别只看R²
模型预测的R²达到0.8,是不是就稳了?不一定。我见过R²很高但交易信号一塌糊涂的情况。
为什么?因为预测精度和交易收益是两码事。模型可能把基差的小波动预测得很准,但真正赚钱的大趋势反而没抓住。
我的评估指标:
| 指标 | 说明 | 我的经验阈值 |
|---|---|---|
| 方向准确率 | 预测基差涨跌方向是否正确 | > 55% |
| 信号胜率 | 有信号时,开仓后盈利的比例 | > 60% |
| 夏普比率 | 风险调整后收益 | > 1.5 |
| 最大回撤 | 策略净值从峰值回落的最大幅度 | < 15% |
我的经验: 方向准确率比R²重要得多。一个R²只有0.3但方向准确率60%的模型,实盘表现往往好于R²=0.8但方向准确率52%的模型。
16.7 避坑指南:LSTM在基差交易中的常见问题
最后,分享几个我踩过的坑:
- 数据泄露: 归一化时用了全量数据的min/max,导致未来信息泄露。正确做法:只用训练集计算scaler参数。
- 序列长度选择: 我试过lookback=60,结果模型学到的全是长期趋势,对短期反转毫无反应。后来改成20,效果反而更好。
- 预测步长: 预测未来1天,信号噪声太大;预测未来10天,模型误差累积严重。5天是个不错的折中。
- 模型更新频率: 不要每天重新训练。我习惯每周训练一次,用最新数据微调。
嗯,LSTM不是万能药。但它确实能捕捉到传统模型忽略的非线性模式。如果你能把数据处理好、阈值设合理,这套端到端的流程在基差交易里是能稳定盈利的。
这套流程,我跑了快两年。从最初的手工调参,到后来加入自动化早停,再到现在的端到端信号生成,每一步都是踩坑踩出来的。希望你能少走弯路。