清华大学iCenter2023-AI量化金融模型预测挑战赛

摘要:

合集:AI案例-ML-泛金融业
赛题:AI量化模型预测挑战赛
主办方:清华大学iCenter
主页:https://challenge.xfyun.cn/topic/info?type=quantitative-model&ch=vWxQGFU
AI问题:时序预测问题
数据集:训练集和验证集包括10只不公开股票、和79个交易日的快照数据,包括5档买入卖出量/买入卖出量价、中间价、交易量等数据。
数据集价值:利用过往及当前股票交易数据进行模型训练,预测未来N个变化周期后的中间价和移动方向。
解决方案:创建并训练 LightGBM 模型。

一、赛题描述

量化金融(Quantitative Finance)是利用数学、统计学、计算机科学和金融理论相结合的方法,通过建立数学模型和算法来分析市场数据、制定投资策略或管理金融风险的学科领域。其核心是通过数据驱动的方式,将金融问题转化为可计算的定量模型,以实现更高效、更客观的决策。由于市场博弈参与个体的差异性和群体效应的复杂性,量化金融极具挑战与重大的机遇的特点。本赛事通过大数据与机器学习的方法和工具,理解市场行为的原理,通过数据分析和模型创建量化策略,采用历史数据,验证量化策略的有效性,并且通过实时数据进行评测。任务为利用过往及当前数据预测未来中间价的移动方向,在数据上进行模型训练与预测。

二、数据集说明

数据集

训练集和验证集包括10只不公开股票、和79个交易日的快照/L1-snapshot数据。前64个交易日为训练数据,用于训练;后15个交易日为测试数据,不能用于训练。数据已进行规范化和隐藏处理,包括5档买入卖出量/买入卖出量价、中间价、交易量等数据。

  • 行情频率:3秒一个数据点,也称为1个Tick的快照/snapshot。Tick 是金融产品(如股票、期货、外汇)价格变动的最小增量或减量。
  • 每个数据点包括当前最新成交价/五档量价/过去3秒内的成交金额等数据。
  • 训练集中每个数据点包含5个预测标签的标注; 允许利用过去不超过100Tick(包含当前Tick)的数据,预测未来N个Tick后的中间价移动方向。
  • 预测时间跨度:5、10、20、40、60个Tick。
  • 5个预测任务:即在t时刻,分别预测:t+5Tick,t+10Tick,t+20Tick,t+40Tick,t+60Tick以后的最新中间价、相较t时刻的中间价、下跌/不变/上涨。

文件说明

训练数据sym0组:

  • snapshot_sym0_date0_am.csv 和 snapshot_sym0_date0_pm.csv
  • snapshot_sym0_date1_am.csv 和 snapshot_sym0_date1_pm.csv
  • snapshot_sym0_date63_am.csv 和 snapshot_sym0_date63_pm.csv

其中训练数据包括sym0组、sym1组、到sym9组。

测试数据sym0组:

  • snapshot_sym0_date64_am.csv 和 snapshot_sym0_date64_pm.csv
  • snapshot_sym0_date65_am.csv 和 snapshot_sym0_date65_pm.csv
  • snapshot_sym0_date78_am.csv 和 snapshot_sym0_date78_pm.csv

其中训练数据包括sym0组、sym1组、到sym9组。

字段定义

每个训练数据文件的字段定义如下:

字段含义说明
date日期连续/sequantial标号:既保留跨标的的可比性,也隐去实际时间
time时间戳保留实际时间戳,3秒一档。例如9:40:03,9:40:06,。。。
sym标的(仅序号)
close最新价/收盘价以涨跌幅表示
amount_delta成交量变化从上个Tick到当前Tick发生的成交金额
n_midprice中间价标准化后的中间价,以涨跌幅表示
n_bid1买一价标准化后的买一价,以下类似
n_bsize1买一量
n_bid2买二价
n_bsize2买二量
n_bid3买三价
n_bsize3买三量
n_bid4买四价
n_bsize4买四量
n_bid5买五价
n_bsize5买五量
n_ask1卖一价
n_asize1卖一量
n_ask2卖二价
n_asize2卖二量
n_ask3卖三价
n_asize3卖三量
n_ask4卖四价
n_asize4卖四量
n_ask5卖五价
n_asize5卖五量
label55Tick价格移动方向5Tick之后中间价相对于当前Tick的移动方向,0为下跌,1为不变,2为上涨。
label1010Tick价格移动方向
label2020Tick价格移动方向
label4040Tick价格移动方向
label6060Tick价格移动方向

中间价说明:

  • 当买一卖一均不为0时,中间价:n_midprice = (n_bid1 + n_ask1) /2
  • 当有一方为0时,中间价取不为0的价格
  • 否则置为NA

价格移动方向标注说明:

  • 和通常定义不同,为了计算方便,这里以涨跌幅为基准
  • 认定方法:
    • 若N个Tick之后的价格较当前Tick价格的涨跌幅上升超过a,则认为上涨,标注为2-上涨;
  • 若下降幅度超过a,则认为下跌,标注为0-下跌;
  • 否则认为价格不变,标注为1-不变
  • 计算:Label (N,t) = f ( n_midprice(t+N) – n_midprice(t) )
  • 其中 f (x)
    • 当 x < – a 时候,取值为 0-下跌
    • 当 – a <= x <= – a 时候,取值为 1-不变
    • 当 a < x 时候,取值为 2-上涨
  • 当N=5,10时,a = 0.0005
  • 当N=20,40,60时,a = 0.001

数据集版权许可协议

CC BY-NC-SA 4.0

三、解决方案样例

解决方案

源码:AI_Quantitative_Model_Forecast.ipynb

这个源码实现了一个基于LightGBM的量化金融预测模型,用于预测股票价格的涨跌趋势。目标是:

  • 通过历史市场数据预测未来5、10、20、40和60个时间单位的涨跌趋势
  • 使用LightGBM作为基础模型
  • 采用交叉验证评估模型性能

安装开发库

参考文章《安装和使用传统机器学习开发包》,安装LightGBM等开发包。

【本样例运行环境的关键版本信息】
python                   3.12.3
lightgbm                 3.3.0

以下为工作流程:

1、导入相关系统库

import pandas as pd
import numpy as np
import glob
from joblib import delayed, Parallel
from tqdm import notebook
import lightgbm as lgb
from sklearn.model_selection import cross_val_predict
from sklearn.metrics import f1_score

2. 数据准备

数据加载

  • ./data/train/./data/test/目录加载训练和测试数据
  • 训练集包含1225个文件,测试集包含296个文件
  • 每个文件包含约2000行记录,28列特征
train_paths = glob.glob('./data/train/*')
len(train_paths)
test_paths = glob.glob('./data/test/*')
len(test_paths)

df = pd.read_csv(glob.glob('./data/train/*')[1])
df = df.iloc[:, 4:]
df

df = pd.read_csv(glob.glob('./data/test/*')[1])
df = df.iloc[:, 4:]
df.columns

输出:

1225 #训练集文件
296 #测试集文件

1999 rows × 28 columns

Index(['n_close', 'amount_delta', 'n_midprice', 'n_bid1', 'n_bsize1', 'n_bid2',
      'n_bsize2', 'n_bid3', 'n_bsize3', 'n_bid4', 'n_bsize4', 'n_bid5',
      'n_bsize5', 'n_ask1', 'n_asize1', 'n_ask2', 'n_asize2', 'n_ask3',
      'n_asize3', 'n_ask4', 'n_asize4', 'n_ask5', 'n_asize5'],
    dtype='object')

数据特征

原始数据包含以下主要特征:

  • 价格相关:n_close(收盘价), n_midprice(中间价), n_bid1-5(买价), n_ask1-5(卖价)
  • 成交量相关:amount_delta, n_bsize1-5(买量), n_asize1-5(卖量)
  • 标签:label_5, label_10, label_20, label_40, label_60(未来不同时间段的涨跌标签)

3. 特征工程

base_feature函数实现了核心特征工程逻辑:

  1. 原始特征:保留所有23个原始特征
  2. 衍生特征:为每个原始特征创建6个衍生特征
    • 当前值与过去3/10/20个时间点的均值差值
    • 当前值与过去3/10/20个时间点的最大值差值
  3. 标签:如果是训练数据,保留5个标签列

最终每个样本有23*(1+6)=161个特征,加上5个标签列,共166列。

def base_feature(path, train=True):
   df_feat = []
   df = pd.read_csv(path)
   for idx, row in enumerate(df.iterrows()):
       idx_feat = []
       for col in ['n_close', 'amount_delta', 'n_midprice', 'n_bid1', 'n_bsize1', 'n_bid2',
                   'n_bsize2', 'n_bid3', 'n_bsize3', 'n_bid4', 'n_bsize4', 'n_bid5',
                   'n_bsize5', 'n_ask1', 'n_asize1', 'n_ask2', 'n_asize2', 'n_ask3',
                   'n_asize3', 'n_ask4', 'n_asize4', 'n_ask5', 'n_asize5']:

           idx_feat.append(row[1][col])

           if idx == 0:
               idx_feat.append(np.nan)
           else:
               idx_feat.append(row[1][col] - df.iloc[max(0, idx-3):idx][col].mean())
               idx_feat.append(row[1][col] - df.iloc[max(0, idx-10):idx][col].mean())
               idx_feat.append(row[1][col] - df.iloc[max(0, idx-20):idx][col].mean())
               
               idx_feat.append(row[1][col] - df.iloc[max(0, idx-3):idx][col].max())
               idx_feat.append(row[1][col] - df.iloc[max(0, idx-10):idx][col].max())
               idx_feat.append(row[1][col] - df.iloc[max(0, idx-20):idx][col].max())

       if train:
           idx_feat += list(row[1].iloc[-5:])
       
       df_feat.append(idx_feat)
   
   return pd.DataFrame(df_feat)

4. 并行处理

使用joblib.Parallel并行处理所有训练和测试文件:

  • 并行度设置为5(n_jobs=5)
  • 使用tqdm.notebook显示进度条
  • 最终将所有结果合并为一个DataFrame
# 并行处理 train_paths 列表中的每个路径,通过调用 base_feature 函数,并使用进度条显示处理进度
# n_jobs=5 参数指定了并行运行的作业数量,即同时最多有 5 个 base_feature 函数在后台运行
# delayed 是 joblib 库中的一个函数,用于延迟(或包装)函数的执行。它告诉 joblib 在并行计算时需要执行哪个函数以及传递哪些参数
train_feat = Parallel(n_jobs=5)(delayed(base_feature)(path, True) for path in notebook.tqdm(train_paths[:]))

test_feat = Parallel(n_jobs=5)(delayed(base_feature)(path, False) for path in notebook.tqdm(test_paths[:]))

# 使用 pd.concat 将所有 DataFrame 合并为一个
train_feat = pd.concat(train_feat, axis=0, ignore_index=True)

# 删除在任何一列中包含 NaN 的行
train_feat = train_feat.dropna()
train_feat.head(10)

5. 模型构建与训练

模型选择

使用LightGBM分类器(LGBMClassifier)作为基础模型,默认参数。

# cross_val_predict 是 scikit-learn 库中的一个函数,用于执行交叉验证并返回每个样本的预测结果
val_pred = cross_val_predict(
   lgb.LGBMClassifier(),
   train_feat.iloc[:, :-5],  # Pandas 的 .iloc 索引方法,表示选择所有行(:),以及除了最后五列之外的所有列作为特征
   train_feat.iloc[:, -5]  # 表示选择了 train_feat 数据框的最后五列作为目标变量
)

print(f1_score(train_feat.iloc[:, -5], val_pred, average='macro'))

训练策略

  1. 使用交叉验证(cross_val_predict)评估模型在label_5上的性能
    • 计算macro F1分数(0.402)
  2. 训练5个独立的模型,分别预测不同时间段的标签:
    • m5: 预测label_5
    • m10: 预测label_10
    • m20: 预测label_20
    • m40: 预测label_40
    • m60: 预测label_60
m5 = lgb.LGBMClassifier()
m5.fit(train_feat.iloc[:, :-5], train_feat.iloc[:, -5])

m10 = lgb.LGBMClassifier()
m10.fit(train_feat.iloc[:, :-5], train_feat.iloc[:, -4])

m20 = lgb.LGBMClassifier()
m20.fit(train_feat.iloc[:, :-5], train_feat.iloc[:, -3])

m40 = lgb.LGBMClassifier()
m40.fit(train_feat.iloc[:, :-5], train_feat.iloc[:, -2])

m60 = lgb.LGBMClassifier()
m60.fit(train_feat.iloc[:, :-5], train_feat.iloc[:, -1])

6. 预测与输出

对测试集进行涨跌趋势预测:

  1. 对每个测试文件使用相同的特征工程处理
  2. 用5个模型分别预测不同时间段的标签
  3. 将预测结果保存为CSV文件到./submit/目录
for df, path in zip(test_feat, test_paths):
   sub = pd.DataFrame({
       'uuid': range(len(df)),
       'label_5': m5.predict(df),
       'label_10': m10.predict(df),
       'label_20': m20.predict(df),
       'label_40': m40.predict(df),
       'label_60': m60.predict(df)
  })
   sub.to_csv('./submit/' + path.split('/')[-1], index=None)

输出预测数据样例:

0为下跌,1为不变,2为上涨。

uuid    label_5 label_10    label_20    label_40    label_60
0 1 1 1 1 1
1 1 2 1 2 2
2 1 2 2 2 2
3 1 2 2 2 2
4 1 2 2 2 0
5 1 2 2 2 2
6 2 2 2 2 2
7 2 2 2 2 2
...

源码开源协议

GPL-v3

四、获取案例套装

需要登录后才允许下载文件包。登录

发表评论