当前位置: 首页 > news >正文

[QMT量化交易小白入门]-八十四、LSTM模型对期货市场的秒级Tick数据进行预测

本专栏主要是介绍QMT的基础用法,常见函数,写策略的方法,也会分享一些量化交易的思路,大概会写100篇左右。
QMT的相关资料较少,在使用过程中不断的摸索,遇到了一些问题,记录下来和大家一起沟通,共同进步。

文章目录

      • 相关阅读
      • 一、数据加载与初步校验
      • 二、特征工程与目标设定
      • 三、数据集划分策略
      • 四、标准化归一化处理
      • 五、LSTM输入结构构造
      • 六、网络架构搭建
      • 七、可视化与性能评估
      • 八、完整执行流程解析
      • 九、模型部署与结果保存

相关阅读

小白也能做量化:零门槛QMT、Ptrade免费送
量化交易入门:如何在QMT中配置Python环境,安装第三方依赖包
年化收益达到了70%,增加了动态仓位权重调整后的全球核心资产轮动策略(含python代码解析)


前面介绍了 LSTM模型基于股票三秒tick数据的预测,但是由于制度的限制,大A对于高频日内交易不太友好,更合适的标的是期货,期货每秒钟都有tick数据,日内交易也更方便。本文将完整解析如何利用Python构建LSTM模型,对期货市场的秒级Tick数据进行精准预测。所有实现均基于真实数据验证,代码可复用并扩展。

一、数据加载与初步校验

def load_data(filepath):"""加载tick数据CSV文件,格式包含:time,lastPrice,open,high,low,lastClose,amount,volume,pvolume等字段"""df = pd.read_csv(filepath)return df

这段代码的核心作用是读取存储在本地文件中的原始交易记录。特别注意三个关键点:

  1. 字段兼容性:函数注释明确列出了支持的数据列结构,这是后续处理的基础保障。实际使用时需确保CSV头部与文档描述完全一致;
  2. 内存优化:pandas会自动推断每列的数据类型,对于数值型特征(如价格、成交量)会分配合适的存储空间;
  3. 异常捕获机制:主函数中实现了双重容错机制——当主文件缺失时自动切换至备份文件,这在生产环境中尤为重要。

main()函数里可以看到完整的调用流程:

data_file = os.path.join(TICK_DATA_DIR, 'MA511_2025.csv')
try:df = load_data(data_file)if len(df) > 10000:df = df.tail(10000)        print(f"成功加载数据文件: {data_file}, 数据量: {len(df)}条")
except FileNotFoundError:# 尝试备用文件...

这里有两个重要设计考量:一是限制最大样本量为1万条以防止内存溢出;二是通过异常处理保证程序健壮性。

二、特征工程与目标设定

def preprocess_data(df):# 解析askVol和bidVol数组,取第一个值df['askVol'] = df['askVol'].apply(lambda x: eval(x)[0] if isinstance(x, str) else x[0])df['bidVol'] = df['bidVol'].apply(lambda x: eval(x)[0] if isinstance(x, str) else x[0])# 选择需要的列 - 使用lastPrice作为主价格,添加volume,amount,askVol,bidVol作为特征features = df[['lastPrice', 'volume', 'amount', 'askVol', 'bidVol']]target = df['lastPrice'].shift(-1)  # 预测下一条的lastPrice# 移除最后一行(没有目标值)features = features[:-1]target = target[:-1]return features, target

该阶段的数据处理体现了金融时间序列的特殊性:

  1. 挂单量解析:由于原始数据中的买卖盘口深度可能以字符串形式存在(如"[100,200]"),需要提取首个报价量作为有效信号;
  2. 滞后窗口构建:通过shift(-1)创建自回归目标变量,即用当前时刻的特征预测下一时刻的价格走势;
  3. 对齐修正:因移位操作导致末尾产生NaN值,必须同步裁剪特征矩阵和标签向量保持维度一致。

三、数据集划分策略

def split_data(features, target, test_size=0.2):X_train, X_test, y_train, y_test = train_test_split(features, target, test_size=test_size, shuffle=False)return X_train, X_test, y_train, y_test

区别于传统机器学习任务,这里特别设置了shuffle=False参数。这是因为时间序列具有严格的先后顺序关系,随机打乱会破坏数据的时序特性。采用前80%作为训练集、后20%作为测试集的方式,能更真实地模拟线上环境的数据分布。

四、标准化归一化处理

def normalize_data(X_train, X_test, y_train, y_test):# 特征归一化feature_scaler = MinMaxScaler()X_train_scaled = feature_scaler.fit_transform(X_train)X_test_scaled = feature_scaler.transform(X_test)# 目标值归一化target_scaler = MinMaxScaler()y_train = y_train.values.reshape(-1, 1)y_test = y_test.values.reshape(-1, 1)y_train_scaled = target_scaler.fit_transform(y_train)y_test_scaled = target_scaler.transform(y_test)return X_train_scaled, X_test_scaled, y_train_scaled, y_test_scaled, feature_scaler, target_scaler

实施双通道标准化的原因包括:

  1. 消除量纲差异:不同特征的数量级相差较大(如价格约几百元而成交量可达数十万手),统一缩放到[0,1]区间可避免大数值主导损失函数;
  2. 独立同分布假设:训练集拟合得到的变换参数直接应用于测试集,确保评估过程不受尺度干扰;
  3. 逆变换准备:保留两个Scaler对象用于后续反归一化操作,使模型输出回归到原始业务单位。

五、LSTM输入结构构造

def create_lstm_dataset(data, target, window_size=WINDOW_SIZE):X, y = [], []for i in range(len(data) - window_size - PREDICT_STEP):  # 减去PREDICT_STEP以确保能预测指定步长的数据X.append(data[i:i+window_size])y.append(target.iloc[i+window_size+PREDICT_STEP])  # 预测指定步长后的lastPricereturn np.array(X), np.array(y)

这是整个方案最关键的环节之一:

  1. 滑动窗口机制:每个样本由连续window_size个时间点组成输入序列,对应未来PREDICT_STEP步长的单个预测目标;
  2. 边界控制:循环终止条件精确计算可用样本数,防止索引越界错误;
  3. 三维张量转换:最终生成的形状为(samples, steps, features)的标准LSTM输入格式。

例如当window_size=60时,模型每次会分析过去60秒的市场状态来推断之后的价格走向。这种设计既保留了局部细节又捕捉了长期趋势。

六、网络架构搭建

def build_lstm_model(input_shape):model = Sequential()model.add(LSTM(50, return_sequences=True, input_shape=input_shape))model.add(LSTM(50))model.add(Dense(1))  # 仍然输出1个值model.compile(optimizer='adam', loss='mse')return model

双层LSTM结构的设计理念如下:

  1. 第一层返回序列:设置return_sequences=True保留中间层的隐藏状态输出,增强特征提取能力;
  2. 第二层压缩时空信息:将时序特征编码为固定长度的向量表示;
  3. 单节点全连接层:直接映射到标量输出,适用于回归任务;
  4. 自适应学习率:Adam优化器自动调整参数更新步伐,配合均方误差损失函数形成稳定的训练过程。

这种堆叠式结构相比单层网络能更好地捕获复杂模式,同时避免了过度拟合风险。

七、可视化与性能评估

def plot_results(y_train, y_test, y_train_pred, y_test_pred):plt.rcParams['font.sans-serif'] = ['SimHei']  # 设置中文字体plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题plt.figure(figsize=(12, 6))# 确保所有数据是一维数组y_train = y_train.values.flatten() if hasattr(y_train, 'values') else y_train.flatten()y_test = y_test.values.flatten() if hasattr(y_test, 'values') else y_test.flatten()y_train_pred = y_train_pred.flatten()y_test_pred = y_test_pred.flatten()# 绘制训练集实际值和预测值plt.plot(y_train, label='实际训练值')plt.plot(y_train_pred, label=f'预测训练值({PREDICT_STEP}条后)')# 绘制测试集实际值和预测值test_start = len(y_train)test_end = test_start + min(len(y_test), len(y_test_pred))  # 取最小长度确保维度匹配plt.plot(range(test_start, test_end), y_test[:test_end-test_start], label='实际测试值')plt.plot(range(test_start, test_end), y_test_pred[:test_end-test_start], label=f'预测测试值({PREDICT_STEP}条后)')plt.legend()plt.xlabel('时间步长')plt.ylabel('最新价格(lastPrice)')plt.title(f'LSTM最新价格预测({PREDICT_STEP}条后)')plt.show()

绘图模块实现了四个核心功能:

  1. 双语支持:配置中文字体解决乱码问题;
  2. 动态适配:自动处理Pandas Series与NumPy数组的类型转换;
  3. 分段展示:清晰区分训练阶段和测试阶段的预测效果;
  4. 量化标注:图例明确标示预测延迟步长,便于对比分析。

结合具体的误差指标计算:

mae = mean_absolute_error(y_test_target, y_test_pred)
rmse = np.sqrt(mean_squared_error(y_test_target, y_test_pred))
print(f"测试集平均绝对误差(MAE): {mae:.4f}")
print(f"测试集均方根误差(RMSE): {rmse:.4f}")

建议优先关注MAE指标,因为它直接反映预测偏差的实际货币价值。而RMSE则更适合检测极端异常情况。

八、完整执行流程解析

主函数串联起各个模块并添加了必要的安全检查:

def main():# ...前面步骤省略...# 验证数据量是否足够min_required = WINDOW_SIZE + PREDICT_STEP + 1  # 窗口大小+预测步长+1if len(df) < min_required:raise ValueError(f"数据量不足,至少需要{min_required}条数据,当前只有{len(df)}条")# ...后续步骤省略...# 检查数据集是否为空if len(X_train_lstm) == 0 or len(X_test_lstm) == 0:raise ValueError("数据集为空,请检查数据量是否足够(至少需要{}条数据)".format(WINDOW_SIZE + PREDICT_STEP))

这些前置条件判断能有效规避常见错误:

  1. 最小样本校验:确保有足够的历史数据构建首个完整窗口;
  2. 空集过滤:防止因参数设置不当导致无效的训练批次;
  3. 索引边界保护:在获取预测目标时进行范围校验,避免数组越界。

九、模型部署与结果保存

# 保存模型(HDF5格式)
save_model(model, os.path.join(MODEL_DIR, 'lstm_ma_tick.h5'))# 保存测试集预测结果(包含时间列)
test_time_indices = range(len(X_train_lstm), len(X_train_lstm) + len(y_test_lstm))
test_results = pd.DataFrame({'time': df.iloc[test_time_indices]['time'].values,'actual': y_test_target.flatten(),'predicted': y_test_pred.flatten()
})
test_results.to_csv(os.path.join(RESULT_DIR, 'lstm_ma_tick.csv'), index=False)

生产级应用需要考虑两个方面:

  1. 模型持久化:使用Keras默认的HDF5格式保存完整网络结构和权重参数;
  2. 可追溯性:将预测结果与原始时间戳关联存储,方便事后复盘分析。

训练预测结果如下:
在这里插入图片描述

Epoch 1/10
496/496 [==============================] - 5s 7ms/step - loss: 0.0034
Epoch 2/10
496/496 [==============================] - 4s 7ms/step - loss: 0.0016
Epoch 3/10
496/496 [==============================] - 4s 7ms/step - loss: 0.0016
Epoch 4/10
496/496 [==============================] - 4s 7ms/step - loss: 0.0015
Epoch 5/10
496/496 [==============================] - 4s 8ms/step - loss: 0.0016
Epoch 6/10
496/496 [==============================] - 4s 7ms/step - loss: 0.0015
Epoch 7/10
496/496 [==============================] - 4s 7ms/step - loss: 0.0015
Epoch 8/10
496/496 [==============================] - 4s 7ms/step - loss: 0.0015
Epoch 9/10
496/496 [==============================] - 4s 7ms/step - loss: 0.0015
Epoch 10/10
496/496 [==============================] - 4s 7ms/step - loss: 0.0015
496/496 [==============================] - 2s 3ms/step
121/121 [==============================] - 0s 3ms/step
警告:预测步长超出数据范围,使用最后可用数据
测试集平均绝对误差(MAE): 2.0597
测试集均方根误差(RMSE): 2.9153

示例中使用固定参数(如units=50, batch_size=32),但实际应用时应系统地进行网格搜索:

参数类型推荐范围调优方向
LSTM单元数[32, 64, 128]随复杂度增加而提升效果
Dropout比率[0.1, 0.2, 0.3]平衡正则化强度
学习率初值[1e-3, 1e-4, 1e-5]根据收敛速度调整
批量大小[16, 32, 64]权衡显存占用与梯度稳定性

后续可以使用WalkForward交叉验证方法,它能更好地适应非平稳的时间序列特性。具体实现时可将数据集按时间段划分为多个区块,依次作为验证集进行滚动预测。

基础量价数据已包含大部分有效信息。盲目添加MACD、RSI等衍生指标可能导致多重共线性,反而降低模型泛化能力,后续可以尝试,但要先做PCA降维处理。

没有万能模型,只有最适合当前市场环境的算法组合。

http://www.xdnf.cn/news/1362781.html

相关文章:

  • AI背后使用的技术
  • 《信息检索与论文写作》实验报告一 EI数据库检索
  • 【文献阅读】SparseGPT: Massive Language Models Can be Accurately Pruned in One-Shot
  • ios webgl音频问题
  • 设置密钥连接服务器
  • Charles安装到使用全流程教程
  • Gemini 2.5 Flash-Lite 与 GPT-5-mini:高性能低成本模型,如何选择?
  • 第十七节:高级材质 - ShaderMaterial揭秘
  • 物联网时序数据库IoTDB架构解析
  • h5和微信小程序查看pdf文件
  • DrissionPage 能控制火狐或edge吗
  • 20.14 QLoRA微调Whisper-Large-v2终极指南:3倍速训练+显存直降68%调参秘籍
  • ADB 调试工具的学习[特殊字符]
  • 【智慧城市】2025年中国地质大学(武汉)暑期实训优秀作品(2):智慧城市西安与一带一路
  • 技术速递|使用 AI 应用模板扩展创建一个 .NET AI 应用与自定义数据进行对话
  • 通过C#上位机串口写入和读取浮点数到stm32实战5(通过串口读取bmp280气压计的数值并在上位机显示)
  • .NET表格控件Spread .NET v18.0——支持富文本、增强PDF导出
  • 算法学习8.25
  • 如何生成雪碧图和 WEBVTT
  • Elasticsearch脑裂紧急处理与预防
  • [React]Antd Upload组件上传多个文件
  • 微服务商城构筑其一
  • VIVO/OPPO手机,显示5G开关
  • 【Wrangler(Cloudflare 的官方 CLI)和 npm/npx 的区别一次讲清】
  • 大模型面试题剖析:Pre-Norm与Post-Norm的对比及当代大模型选择Pre-Norm的原因
  • openharmony之DRM开发:数字知识产权保护揭秘
  • ESP8266学习
  • 迁移面试题
  • 将跨平台框架或游戏引擎开发的 macOS 应用上架 Mac App Store
  • Docker基本使用方法和常用命令