第二十五讲:基差的机器学习预测——随机森林与LSTM在基差预测中的实战
各位同学,今天我们来聊点硬核的。前面我们讲了统计模型、讲了时间序列,但说实话,在真实的交易环境里,基差这东西太复杂了。它受库存、受情绪、受政策、受资金面……你想想看,这么多因素搅在一起,传统模型有时候真不够用。
所以,我个人的习惯是——遇到这种“多因子、非线性、高噪声”的问题,直接上机器学习。今天我们就拿两个最典型的模型来开刀:随机森林和LSTM。一个代表“传统机器学习”的巅峰,一个代表“深度学习时序”的利器。
核心观点:基差预测不是“预测未来价格”,而是“预测价差的波动规律”。你只要比市场早半步识别出基差的异常偏离,就能吃到回归的利润。
一、为什么是随机森林和LSTM?
我先说说我的选型逻辑。
随机森林,说白了就是一群决策树投票。它不怕过拟合,能处理缺失值,还能输出特征重要性——这一点在金融里太重要了。我在项目中遇到过好几次,用随机森林跑完,发现“近月持仓量变化”这个特征的权重远高于其他,后来我专门盯着这个因子做策略,效果不错。
LSTM呢,它是专门为序列数据设计的。基差本身就是一个时间序列,今天的基差跟昨天、前天、甚至前一周都有关系。LSTM能记住这些“长期依赖”,这是普通神经网络做不到的。
嗯,这里要注意:随机森林适合“截面数据”,比如你拿当前时刻的库存、持仓、波动率去预测当前基差的异常程度;而LSTM适合“时序数据”,比如你用过去N天的基差序列去预测未来1天的基差。
二、数据准备:别让模型“吃垃圾”
做机器学习,有一句话我特别认同:垃圾进,垃圾出。你模型再牛,数据不对也是白搭。
我建议你准备以下特征(以螺纹钢为例):
| 特征类别 | 具体特征 | 说明 |
|---|---|---|
| 价格类 | 现货价格、近月期货价、远月期货价 | 基差计算的基础 |
| 持仓类 | 近月持仓量、远月持仓量、持仓变化率 | 反映资金博弈 |
| 库存类 | 社会库存、钢厂库存、库存变化率 | 供需的直接体现 |
| 波动类 | 历史波动率、隐含波动率 | 市场情绪指标 |
| 时间类 | 距离交割日天数、星期几、月份 | 季节性规律 |
我的小技巧:特征不是越多越好。我一般先用随机森林跑一次,看特征重要性排序,把排名后20%的砍掉。这样既能减少噪声,又能提升训练速度。
三、随机森林实战:特征工程与模型训练
好,我们直接上代码。以下是我在实际项目中用过的简化版本。
import pandas as pd
import numpy as np
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_absolute_error
# 加载数据(假设你已经有了特征矩阵X和标签y)
# X: 包含库存、持仓、波动率等特征
# y: 未来1天的基差变化值
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, shuffle=False
)
# 训练随机森林
rf = RandomForestRegressor(
n_estimators=200,
max_depth=10,
min_samples_leaf=5,
random_state=42
)
rf.fit(X_train, y_train)
# 预测
y_pred = rf.predict(X_test)
# 评估
mae = mean_absolute_error(y_test, y_pred)
print(f"测试集MAE: {mae:.4f}")
# 特征重要性
importance = pd.DataFrame({
'feature': X.columns,
'importance': rf.feature_importances_
}).sort_values('importance', ascending=False)
print(importance.head(10))
我曾经在一次实盘测试中,用这个模型预测沪铜的基差。一开始我加了20多个特征,结果MAE一直下不去。后来我砍掉了“宏观经济指标”这类低频数据,只保留日频数据,MAE直接降了15%。记住:高频预测用高频特征,低频特征只会引入滞后。
四、LSTM实战:时序建模与序列预测
LSTM的用法跟随机森林完全不同。它需要你把数据整理成“样本-时间步-特征”的三维结构。
import numpy as np
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense, Dropout
from sklearn.preprocessing import MinMaxScaler
# 假设你有一个基差序列:basis_series
# 用过去60天的基差预测未来1天
def create_sequences(data, seq_length):
X, y = [], []
for i in range(len(data) - seq_length):
X.append(data[i:i+seq_length])
y.append(data[i+seq_length])
return np.array(X), np.array(y)
# 归一化
scaler = MinMaxScaler()
basis_scaled = scaler.fit_transform(basis_series.reshape(-1, 1))
seq_length = 60
X, y = create_sequences(basis_scaled, seq_length)
# 划分训练集和测试集
split = int(0.8 * len(X))
X_train, X_test = X[:split], X[split:]
y_train, y_test = y[:split], y[split:]
# 构建LSTM模型
model = Sequential([
LSTM(50, return_sequences=True, input_shape=(seq_length, 1)),
Dropout(0.2),
LSTM(50, return_sequences=False),
Dropout(0.2),
Dense(1)
])
model.compile(optimizer='adam', loss='mse')
model.fit(X_train, y_train, epochs=50, batch_size=32, validation_split=0.1)
# 预测
y_pred_scaled = model.predict(X_test)
y_pred = scaler.inverse_transform(y_pred_scaled)
y_test_actual = scaler.inverse_transform(y_test.reshape(-1, 1))
避坑指南:我曾经犯过一个错误——直接用原始基差训练LSTM,结果模型死活不收敛。后来发现是数据尺度问题。基差有时候是-200,有时候是+500,这种大范围波动会让LSTM的梯度爆炸。一定要做归一化!
五、随机森林 vs LSTM:到底选哪个?
这个问题我经常被问到。我的回答是:看你的数据形态和预测目标。
- 如果你做“截面预测”——比如今天收盘后,用当前所有品种的数据判断哪个品种的基差被高估/低估,用随机森林。它快,可解释性强。
- 如果你做“时序预测”——比如用过去60天的基差序列预测明天的基差,用LSTM。它能捕捉到趋势和周期。
- 如果你两个都想做——我建议你把随机森林的特征输出作为LSTM的额外输入,做一个“混合模型”。我在一次比赛中用过这个思路,效果比单独用任何一个都好。
六、核心逻辑框架图
下面这张图是我自己总结的基差机器学习预测流程,你照着这个框架走,基本不会跑偏。
七、实战中的几个坑
最后,我掏心窝子说几个我踩过的坑:
- 不要用未来数据。 我见过有人用“当天的收盘价”去预测“当天的基差”,这等于作弊。一定要确保你的特征在预测时点是已知的。
- 注意样本外测试。 时间序列数据不能随机打乱。我习惯按时间顺序划分,前80%训练,后20%测试。
- 别迷信深度学习。 有时候随机森林的效果比LSTM还好,尤其是数据量不大的时候。我建议你先跑随机森林,把它作为baseline,再考虑要不要上LSTM。
- 回测要带交易成本。 基差策略通常需要频繁换月,手续费和滑点会吃掉不少利润。我吃过这个亏,后来在回测里强制加了2个跳点的滑点成本。
总结一句话:随机森林帮你“看截面”,LSTM帮你“看时序”。两个模型结合起来,你就能从不同维度捕捉基差的波动规律。剩下的,就是不断迭代、不断优化。
公众号:蓝海资料掘金营,微信deep3321