首页 > 其他分享 >Kaggle量化比赛复盘: Optiver - Trading at the Close

Kaggle量化比赛复盘: Optiver - Trading at the Close

时间:2024-03-29 20:00:03浏览次数:24  
标签:Optiver df 模型 Kaggle 特征 test Trading np col

目录

前言

一、开源方案

1. 6th获奖方案(代码未开源)

1.1. 特征工程(关键代码)

1.2. 方案解析

2. 7th获奖方案(开源)

2.1. 特征工程

2.2. 特征工程

3. 9th获奖方案(半开源)

3.1. 特征构造

3.2. 特征筛选

3.3. 模型

3.4. zero_sum(标签后处理)

4. 14th获奖方案(开源)

4.1. 方案开源链接

4.2. zero_sum(标签后处理)

5. 15th获奖方案(半开源)

5.1. 特征工程

5.2. 模型

5.2. 时序交叉验证/滚动训练

5.3. zero_sum(标签平滑技术)

6. 23th获奖方案(半开源)

6.1. 特征工程

6.2. 模型

6.3. CV交叉验证

6.4. 关于NN取舍、在线学习的思考

7. 25th获奖方案(半开源)

7.1. 特征工程

7.2. 模型

二、比赛Trick/Fancy Idea

三、思考


前言

基于集合竞价开始以来经过 N 秒的行情数据,进行target预测。

比赛链接:https://www.kaggle.com/competitions/optiver-trading-at-the-close(科学上网)


一、开源方案

1. 6th获奖方案(代码未开源)

kaggle:https://www.kaggle.com/competitions/optiver-trading-at-the-close/discussion/486040

overview:少量特征工程(特征工程在本方案中占比不大)+深度学习(3*Transformer+1*GRU)+滚动训练/增量学习+zero_sum后处理。

1.1. 特征工程(关键代码)

# 特征工程
# (1)集合竞价前n秒数据分桶
df['seconds_in_bucket_flag_1'] = df['seconds_in_bucket'] >= 300 - 60
df['seconds_in_bucket_flag_2'] = df['seconds_in_bucket'] >= 300
df['seconds_in_bucket_flag_3'] = df['seconds_in_bucket'] >= 480 - 60
df['seconds_in_bucket_flag_4'] = df['seconds_in_bucket'] >= 480

# (2)常规量化因子
df["volume"] = df['ask_size'] + df['bid_size']
df["mid_price"] = (df['ask_price'] + df['bid_price']) / 2
df["liquidity_imbalance"] = (df['bid_size'] - df['ask_size']) / df["volume"]
df["matched_imbalance"] = (df['imbalance_size'] - df['matched_size']) / (df['imbalance_size'] + df['matched_size'])
df["size_imbalance"] = df['bid_size'] / df['ask_size']
df['harmonic_imbalance'] = 2 / ((1 / df['bid_size']) + (1 / df['ask_size'] ))


# (3)基于数学算子的常规特征
from itertools import combinations
prices = ["reference_price", "far_price", "near_price", "ask_price", "bid_price", "wap"]
for c in combinations(prices, 2):
    df[f"{c[0]}_{c[1]}_imb"] = df.eval(f"({c[0]} - {c[1]})/({c[0]} + {c[1]})")

1.2. 方案解析

(1)数据预处理:用0填充缺失值,特征标准化;
(2)特征工程:模型共35-36个特征,对seconds_in_bucket(集合竞价前N秒数据进行数值分桶),以及1.1部分的其它特征工程(在本方案中,特征工程work占比不大);
(3)建模:3*transformers + 1* GRU。训练过程采用滚动训练/在线增量学习训练模型,并在滚动过程中使用最新的20day数据评估模型。此外,由于评估指标在每次训练后都不稳定,方案使用指数移动平均值来平滑数值并比较模型;
(4)后处理(比赛trick):对pre进行zero_sum处理。除一个模型外,所有模型在训练时都附加了一个约束条件,即模型输出总和为零;
(5)模型融合:平均加权——(3*transformers+1* GRU)/4。

2. 7th获奖方案(开源)

github:https://github.com/nimashahbazi/optiver-trading-close

kaggle:https://www.kaggle.com/competitions/optiver-trading-at-the-close/discussion/486169

overview:特征工程(手工常规特征、偏差特征)+模型融合(LGB+LSTM、ConvNet)+在线学习滚动更新模型参数;

2.1. 特征工程

常规特征: 

订单簿不平衡:利用公开共享的imb1、imb2等。
趋势指标:采用diff()实现时间变化。
基于交易量的累积:汇总一段时间内的交易量。
全球股票统计:计算历史股票数据的平均值、中位数和标准差。
偏差特征:基于树的模型和神经网络模型都受益于代表偏离中位数的原始特征,如下图所示:

偏差特征(横截面特征):

# 偏差特征/横截面特征/中性化处理
# new_fea = df[feature] - grouped_median,计算每个特征值与其在同一天、同一集合竞价时间分组聚合的中位数(grouped_median)的偏差
# 标准化特征值,更好地识别异常值,减少组间偏差,提高模型性能,增强数据解释性,并便于后续的数据分析工作
  def create_deviation_within_seconds(df, num_features):
      groupby_cols = ['date_id', 'seconds_in_bucket']
      new_columns = {}
      for feature in num_features:
          grouped_median = df.groupby(groupby_cols)[feature].transform('median')
          deviation_col_name = f'deviation_from_median_{feature}'
          new_columns[deviation_col_name] = df[feature] - grouped_median
      return pd.concat([df, pd.DataFrame(new_columns)], axis=1)

2.2. 特征工程

LGB+NN(LSTM and ConvNet models)+在线学习。

3. 9th获奖方案(半开源)

kaggle:https://www.kaggle.com/competitions/optiver-trading-at-the-close/discussion/486868

overview:特征工程+特征筛选(157 features)+3*XGB(different seeds)+在线学习+zero_sum标签平滑技术。

3.1. 特征构造

# (1)特征缩放(横截面特征):根据stock_id分组,基于横截面median进行(也可以加入其他算子,加减乘除等)
size_col = ['imbalance_size','matched_size','bid_size','ask_size']
for _ in size_col:
    train[f"scale_{_}"] = train[_] / train.groupby(['stock_id'])[_].transform('median')

# (2)常规特征工程/聚合
* 订单薄不平衡:imb1、imb2 特征;
* diff特征:diff() on different time window;
* rolling特征:rolling_mean/std on different time window;
* shift特征:shift() on different time window;
* 基于全局股票数据groupby()的统计特征
* MACD系列特征;
* 基于stock_id & seconds_in_bucket进行groupby()的聚合特征。

3.2. 特征筛选

对已构造特征进行分组(10~30个特征一组),逐组加入模型,观察该组特征对模型是否有提升。如果有,再逐个加入,挑选提升效果最好的Top 5~Top 10。最终筛选保留157个特征。

3.3. 模型

3*XGB(different seeds)+在线学习(re-training模型两次,T、T+30)。测试发现LGB和XGB效果相近,但XGB比LGB训练速度快很多。

3.4. zero_sum(标签后处理)

test_df['pred'] = lgb_predictions
test_df['w_pred'] = test_df['weight'] * test_df['pred']
test_df["post_num"] = test_df.groupby(["date_id","seconds_in_bucket"])['w_pred'].transform('sum') / test_df.groupby(["date_id","seconds_in_bucket"])['weight'].transform('sum')
test_df['pred'] = test_df['pred'] - test_df['post_num']

4. 14th获奖方案(开源)

kaggle link: https://www.kaggle.com/competitions/optiver-trading-at-the-close/discussion/485985

overview:特征工程(占主导作用)+模型融合(lgb,xgb,cat)。无滚动训练过程/增量学习/在线学习,纯靠稳定的特征工程和模型融合without shake in private。

4.1. 方案开源链接

https://www.kaggle.com/code/cody11null/14th-place-gold-cat-lgb-refit#FEATURE-ENGINEERING

4.2. zero_sum(标签后处理)

# weight_i * target_i = 0
def weight_adjustment(pred, test_weights, adjustment=True):
    if adjustment==True:
        pred = pred - np.average(pred, weights = test_weights)
    return pred

5. 15th获奖方案(半开源)

github:https://github.com/osyuksel/kaggle-optiver-2024/blob/main/train.py

kaggle:https://www.kaggle.com/competitions/optiver-trading-at-the-close/discussion/486086

overview:特征工程+建模,3*LGB+4*XGB(离线)+1*LGB(在线学习/滚动训练,re-trained every 5 days with a window of 60 days)。

5.1. 特征工程

大部分滚动特征起反效果,同时借鉴了其它方案的特征工程。

5.2. 模型

  • 3*LGB(离线);
  • 4*XGB(离线);
  • 1*LGB(在线学习/滚动训练,re-trained every 5 days with a window of 60 days)。

5.2. 时序交叉验证/滚动训练

按date_id日期id进行n次时序交叉验证,每次间隔5天。

5.3. zero_sum(标签平滑技术)

同3.4. & 4.2.

6. 23th获奖方案(半开源)

kaggle:https://www.kaggle.com/competitions/optiver-trading-at-the-close/discussion/485993

overview:Feature is all you need,特征工程(200~300个——>75个,占主导作用)+树模型(LGB 、CAT、XGB)+NN(MLP, 1D-CNN, and transformer_encoder)+无滚动训练/增量学习过程、舍弃了NN模型。

6.1. 特征工程

  • 日内统计特征;
  • 跨日统计数据(遗传算法挖掘);
  • 截面统计特征。

官网讲述了特征构造思路,但具体如何实现尚无源码。详情见:https://www.kaggle.com/competitions/optiver-trading-at-the-close/discussion/462664

6.2. 模型

  • CatBoost:成为最有效的模型(效果OK);
  • LGB和XGB:表现出相似的性能特征,使模型一起提高了约0.0010至0.0012(效果一般);
  • NN:由MLP、1D-CNN和变压器编码器层组成,最终形成一个完全连接的层(效果较差、最终舍弃)。

6.3. CV交叉验证

6.4. 关于NN取舍、在线学习的思考

未加入滚动训练/增量学习,同时舍弃了NN模型无滚动训练/增量学习——分析数据观察到,纳斯达克在6月至12月期间市场波动很大。担心该模型对11月回撤极其敏感性,可能严重影响未来的数据;舍弃NN模型——权衡NN的稳定性和波动性。

7. 25th获奖方案(半开源)

github:https://github.com/nlztrk/Optiver-Trading-at-the-Close/blob/main/seed_full_train.py

kaggle:https://www.kaggle.com/competitions/optiver-trading-at-the-close/discussion/485967

overview:特征工程+ML模型(2*XGB) + NN模型(LSTM,CNN,Transformer and MLP)。

7.1. 特征工程

# 用于XGB模型训练,NN模型仅使用原始特征
"""
(1)加权WAP;
(2)WAP指数比率;
(3)WAP指数差异;
(4)对数收益和实现波动性(对于wap、ask_price和bid_price等特征的对数收益);
(5)价格差(询价价格和出价价格之间的差);
(6)价差强度(价差流动性不平衡);
(7)成交量(询价量+出价量);
(8)中间价格(询价和出价价格的平均值);
(9)流动性不平衡(出价和询价订单的大小差异,归一化为它们的和);
(10)匹配不平衡(匹配大小的不平衡归一化为匹配大小和不平衡大小的和);
(11)大小不平衡 (出价大小/询价大小);
(12)不平衡动量 (不平衡大小相对于匹配大小随时间变化的变化率);
(13)市场紧迫性 (价格差流动性不平衡);
(14)深度压力(出价和询价大小的差异*远近价格的差异);
(15)价差深度比(价格差/出价和询价大小的总和);
(16)中间价格变动(50秒内中间价格的变动);
(17)谐波不平衡(出价和询价大小的谐波平均值);
(18)反向WAP(从出价和询价价格和大小计算的加权平均价格);
(19)出价-询价价差不平衡交互;
(20)出价-询价价差百分比;
(21)价差与成交量比率(出价-询价价差与匹配大小的比率);
(22)订单簿深度与成交量比率(出价和询价大小之和与匹配大小的比率);
(23)平均交易大小(每秒匹配交易的平均大小);
(24)相对价差(出价-询价价差与WAP的比率);
(25)对所有股票进行排名特征;
"""
# 使用不同种子对5个XGBS进行MAE损失训练,并使用中位数混合生成预测。

7.2. 模型

  • 2*XGB:一个训练特征集1(简化特征)、一个训练特征集1(在简化特征集上增加更多的特征),以探索不同特征组合对模型性能的影响;
  • NN系列模型:LSTM,CNN,Transformer and MLP。仅用原始特征、未添加任何特征工程,对时间戳归一化,对特征log缩放;
  • 无增量学习/滚动训练/时序交叉验证,依赖特征工程+模型鲁棒性。

二、比赛Trick/Fancy Idea

  1. 特征构造:Big Common Feature Improvement by Simple Changes (kaggle.com)
  2. 特征筛选:方法(1)根据CAT等树模评估特征重要性,通过select_features()筛选Top N特征。select_features - CatBoost | CatBoost。方法(2)分组测试——>逐个测试,保留提升效果最好的Top N(详情见3.2部分)。
  3. 解决NN Shake问题:在线学习/增量学习/滚动训练+模型集成(NN+XGB+CAT)+NN dropout 0.6。
  4. 解决Shake问题:“在线/最新数据”和“离线/历史数据”学习混合。模型集成(3*LGB、1*XGB离线训练+1*LGB滚动训练/增量学习)。3*LGB+1*XGB离线训练保证模型稳定性、保留通用知识;加入1个滚动训练/增量学习的LGB,实时更新模型,增强模型的泛化性。
  5.  zero_sum技术(label平滑):https://github.com/gotoConversion/goto_conversion/

    # 通过zero_sum对模型的预测结果进行调整,通过计算和减去加权平均预测值,使得所有股票的预测目标加权和为零;
    # 这是一种常见的归一化技术,特别是在投资组合管理中,确保预测的总体偏差被消除,有助于避免整体市场的偏差对预测结果的影响。
    test_df['pred'] = pred
    test_df['w_pred'] = test_df['weight'] * test_df['pred']
    test_df["post_num"] = test_df.groupby(["date_id","seconds_in_bucket"])['w_pred'].transform('sum') / test_df.groupby(["date_id","seconds_in_bucket"])['weight'].transform('sum')
    test_df['pred'] = test_df['pred'] - test_df['post_num']
    
  6. 减少内存、加快训练速度:reduce_mem_usage()函数,转换数据类型。

    # Memory reduction
    def reduce_mem_usage(df, verbose=0):
        """
        Iterate through all numeric columns of a dataframe and modify the data type to reduce memory usage.
        """;
    
        start_mem = df.memory_usage().sum() / 1024**2
    
        for col in df.columns:
            col_type = df[col].dtype
    
            if col_type != object and col != "target":
                c_min = df[col].min()
                c_max = df[col].max()
    
                if str(col_type)[:3] == "int" or str(col_type)[:4] == "uint":
                    if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max:
                        df[col] = df[col].astype(np.int8)
                    elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max:
                        df[col] = df[col].astype(np.int16)
                    elif c_min > np.iinfo(np.int32).min and c_max < np.iinfo(np.int32).max:
                        df[col] = df[col].astype(np.int32)
                    elif c_min > np.iinfo(np.int64).min and c_max < np.iinfo(np.int64).max:
                        df[col] = df[col].astype(np.int64)
                else:
                    if c_min > np.finfo(np.float16).min and c_max < np.finfo(np.float16).max:
                        df[col] = df[col].astype(np.float32)
                    elif c_min > np.finfo(np.float32).min and c_max < np.finfo(np.float32).max:
                        df[col] = df[col].astype(np.float32)
                    else:
                        df[col] = df[col].astype(np.float32)
        return df
  7. 特征分布漂移分析:对特征逐个进行分布漂移分析,对分布漂移比较严重的特征进行剔除/nan值等填充。 

  8. 参考链接:https://zhuanlan.zhihu.com/p/673383174


三、思考

        在量化领域,开源方案特征工程比较常规,基于领域经验的规则特征、常规统计特征(mean、std、max、min)、横截面特征(偏差特征、rank特征等等)、特征缩放、特征直接的算子计算(加减乘除)等等。在比赛中比较fancy的是:

(1)zero_sum标签平衡技术,可以消除整体市场偏差、提高跨股票的可比性、提高风险管理能力、提高策略的稳健性、避免过度拟合、提高预测的解释性等等;

(2)离线模型、在线模型/模型rolling/增量学习混合,“在线/最新数据”和“离线/历史数据”学习混合,既保持了模型的通用知识,提高模型的稳定性,又通过模型更新提高模型的泛化性;

(3)使用模型增量学习技术,不断更新模型,适应市场行情数据的流动性;

(4)对单个特征进行分布漂移分析,从而找到时序数据分布漂移的根源;

(5)特征筛选方面,使用树模特征筛选功能/分组筛选技术,从数百特征中筛出真正work的特征,避免了模型过拟合现象,加快了运行速度。

(6)其中有几个方案未体现滚动训练/在线学习的思想,时序领域极有可能出现未来数据分布与已有数据分布不一致的情况,没有加入rolling训练在未来数据测试时shake的风险极高,除非特征+模型鲁棒性足够稳定。所以,时序领域,建议加入滚动训练/在线学习的思想。

标签:Optiver,df,模型,Kaggle,特征,test,Trading,np,col
From: https://blog.csdn.net/qq_51175703/article/details/137109118

相关文章

  • 【踩坑随笔】Kaggle安装langchain相关依赖报错
    kaggle执行语句%pipinstalldatasetslangchainsentence_transformerstqdmchromadblangchain_wenxin安装langchain相关依赖报错的时候出现了以下报错主要是版本不匹配,报错什么就再加载什么就可以了,执行下面的语句%pipinstallkeras-core执行结果%pipinstallw......
  • kaggle 大语言模型新赛保银
    比赛类型:LLM文本转写挑战。任务目标是恢复用于转写给定文本的LLM提示语句。在这个竞赛中,参与者将面临识别和复原经LLM改写后文本原始提示的挑战,这是探索如何有效利用LLM进行文本改写的新颖方式。竞赛概述:问题定义:恢复用于转写给定文本的LLM提示。技术挑战:超越传统文本处理......
  • 走进Kaggle的未知领域:性别和年龄推断算法解析
    ​1、环境设置:此环节将加载实现笔记本无缝功能的基本模块,包括NumPy、Pandas和TensorFlow等库。此外,它还建立了关键的环境常数,如图像尺寸和学习率,这对后续分析和模型训练至关重要。#Generalimportosimportkerasimportnumpyasnpimportpandasaspdimporttensorflow......
  • kaggle上的jax框架的环境配置(TPU版本)
    导出时间:2024-01-1821:00:37星期四python版本:Python3.10.13absl-py==1.4.0accelerate==0.25.0aiofiles==22.1.0aiosqlite==0.19.0anyio==4.2.0argon2-cffi==23.1.0argon2-cffi-bindings==21.2.0array-record==0.5.0arrow==1.3.0astroid==3.0.2asttokens==2.4......
  • kaggle使用tensorboard
    参考:https://www.cnblogs.com/jhy-ColdMoon/p/17341992.html需要使用Ngrokimportosimportmultiprocessing!wgethttps://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip!unzipngrok-stable-linux-amd64.zip!./ngrokauthtoken[自己的token]pool=multip......
  • kaggle Open Problems – Single-Cell Perturbations 1st & 2nd place solution summa
    Leaderboard:https://www.kaggle.com/competitions/open-problems-single-cell-perturbations/leaderboard2ndSolution:https://www.kaggle.com/competitions/open-problems-single-cell-perturbations/discussion/458738Code:https://github.com/Eliorkalfon/single_ce......
  • 【Kaggle】AAAMLP读书笔记 Cat-in-the-dat II (优化)
    本人希望从0开始,自己的Kaggle竞赛12月拿到自己的第一块Kaggle奖牌短期内读完AbhishekThakur的Approaching(Almost)AnyMachineLearningProblem并且发博客记录https://github.com/abhishekkrthakur/approachingalmost12月至少发21篇博客每天保持八小时的学习时间Approachingca......
  • 【Kaggle】AAAMLP读书笔记
    本人希望从0开始,自己的Kaggle竞赛12月拿到自己的第一块Kaggle奖牌短期内读完AbhishekThakur的Approaching(Almost)AnyMachineLearningProblem并且发博客记录https://github.com/abhishekkrthakur/approachingalmost12月至少发21篇博客每天保持八小时的学习时间Approachingca......
  • Kaggle:Titanc Survived
    Kaggle:TitancSurvived数据处理对于这个问题,在训练集中给了10列作为特征。其中有一些对结果预测并没有太大影响的PassengerId、Name、Cabin、Ticket。PassengerId可以直接作为pandas读取cvs文件时候的index_col。train_data=pd.read_csv("dataset/train.csv",index_col="P......
  • Kaggle:Otto Group Classification
    Kaggle:OttoGroupClassification数据处理导入相应的包之后,从csv文件中读取数据,指定id列为index列。本身id列也不携带预测信息。同时将训练数据和测试数据拼接在一起。train_data=pd.read_csv("dataset/train.csv",index_col="id")test_data=pd.read_csv("dataset/test.......