摘要:
合集: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 | 卖五量 | |
label5 | 5Tick价格移动方向 | 5Tick之后中间价相对于当前Tick的移动方向,0为下跌,1为不变,2为上涨。 |
label10 | 10Tick价格移动方向 | |
label20 | 20Tick价格移动方向 | |
label40 | 40Tick价格移动方向 | |
label60 | 60Tick价格移动方向 |
中间价说明:
- 当买一卖一均不为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
函数实现了核心特征工程逻辑:
- 原始特征:保留所有23个原始特征
- 衍生特征:为每个原始特征创建6个衍生特征
- 当前值与过去3/10/20个时间点的均值差值
- 当前值与过去3/10/20个时间点的最大值差值
- 标签:如果是训练数据,保留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'))
训练策略
- 使用交叉验证(
cross_val_predict
)评估模型在label_5
上的性能- 计算macro F1分数(0.402)
- 训练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. 预测与输出
对测试集进行涨跌趋势预测:
- 对每个测试文件使用相同的特征工程处理
- 用5个模型分别预测不同时间段的标签
- 将预测结果保存为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