Advertisement

kaggle量化赛金牌方案(第七名解决方案)

阅读量:
在这里插入图片描述

获奖文章(第七名解决方案)

致谢

我衷心感谢 Optiver 和 Kaggle 由其组织的这项比赛。这一挑战为金融市场的时间序列预测问题带来了高度复杂性的研究课题。

方法论

该方法整合了LightGBM和神经网络模型,并对神经网络实施了最低限度的特征工程处理。我们的目标是综合运用这些模型以期减少预测结果的整体波动程度。

特征工程

LightGBM 增强

使用的特征包括:

  • 订单簿失衡 :利用公开分享的imb1、imb2等。
    • 趋势指标 :计算时间序列的变化。
    • 基于成交量的累积量 :计算成交量的总量。
    • 全球股票统计 :分析历史股票数据的集中趋势与波动性特征。
    • 偏差特征 :在线学习模型适用于神经网络和LightGBM模型。

偏差特征和在线学习帮助显著降低了错误率。

复制代码
    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)

神经网络架构

该架构由 LSTM 和卷积网络(ConvNet)模型组成,并通过融合全球范围内的股票统计数据以及偏差特征分析来优化模型的收敛性能。

该神经网络模型的结构已在Kaggle上发布。参考此处讨论:[Optiver Trading at the Close Discussion]

  • ConvNet : Optiver Conv Just IMB 推理清理
  • LSTM : Optiver No FE LSTM 推理清理

验证策略

采用简单的基于时间的拆分进行模型验证。

以下是扩展的一维卷积模型:

复制代码
    def apply_conv_layers(input_layer, kernel_sizes, filters=16, do_ratio=0.5):
    conv_outputs = []
    
    for kernel_size in kernel_sizes:
        conv_layer = Conv1D(filters=filters, kernel_size=kernel_size, activation='relu', padding='same')(input_layer)
        conv_layer = BatchNormalization()(conv_layer)
        conv_layer = Dropout(do_ratio)(conv_layer)
    
        shortcut = conv_layer
    
        conv_layer = Conv1D(filters=filters, kernel_size=kernel_size, padding='same')(conv_layer)
        conv_layer = BatchNormalization()(conv_layer)
        conv_layer = Activation('relu')(conv_layer)
    
        # Add the output of the first Conv1D layer
        conv_layer = Add()([conv_layer, shortcut])
        conv_outputs.append(conv_layer)
    
    concatenated_conv = Concatenate(axis=-1)(conv_outputs)
    flattened_conv_output = Flatten()(concatenated_conv)
    
    return flattened_conv_output
复制代码
    def create_rnn_model_with_residual(window_size, numerical_features, initial_learning_rate=0.001):
    categorical_features = 'seconds_in_bucket'
    categorical_uniques  = { 'seconds_in_bucket' : 55}
    embedding_dim        = {'seconds_in_bucket' : 10}
    
    input_layer = Input(shape=(window_size, len(numerical_features) + 1), name="combined_input")
    
    # Split the input into numerical and categorical parts
    numerical_input = Lambda(lambda x: x[:, :, :-1], name="numerical_part")(input_layer)
    categorical_input = Lambda(lambda x: x[:, :, -1:], name="categorical_part")(input_layer)
    
    first_numerical = Lambda(lambda x: x[:, 0])(numerical_input)
    
    # diffrentiate layers
    def create_difference_layer(lag):
        return Lambda(lambda x: x[:, lag:, :] - x[:, :-lag, :], name=f"difference_layer_lag{lag}")
    
    difference_layers = []
    for lag in range(1, window_size):
        diff_layer = create_difference_layer(lag)(numerical_input)
        padding = ZeroPadding1D(padding=(lag, 0))(diff_layer)  # Add padding to the beginning of the sequence
        difference_layers.append(padding)
    combined_diff_layer = Concatenate(name="combined_difference_layer")(difference_layers)
    
    # Embedding for categorical part
    vocab_size, embedding_dim = categorical_uniques[categorical_features], embedding_dim[categorical_features]
    embedding = Embedding(vocab_size, embedding_dim, input_length=window_size)(categorical_input)
    embedding = Reshape((window_size, -1))(embedding)
    
    first_embedding = Lambda(lambda x: x[:, 0])(embedding)
    
    # Concatenate numerical input and embedding
    # conv_input = concatenate([enhanced_numerical_input, embedding], axis=-1)
    
    kernel_sizes = [2,3]
    do_ratio = 0.4
    
    flattened_conv_output = apply_conv_layers(numerical_input, kernel_sizes, do_ratio=do_ratio)
    flattened_conv_output_cat = apply_conv_layers(embedding, kernel_sizes, do_ratio=do_ratio)
    flattened_conv_output_diff = apply_conv_layers(combined_diff_layer, kernel_sizes, do_ratio=do_ratio)
    
    dense_output = Concatenate(axis=-1)([flattened_conv_output,flattened_conv_output_cat,flattened_conv_output_diff, Reshape((-1,))(combined_diff_layer),first_numerical,first_embedding])
    
    dense_sizes = [512, 256, 128, 64, 32]
    do_ratio = 0.5
    for size in dense_sizes:
        dense_output = Dense(size, activation='swish')(dense_output)
        dense_output = BatchNormalization()(dense_output)
        dense_output = Dropout(do_ratio)(dense_output)
    
    # Output layer
    output = Dense(1, name='output_layer')(dense_output)
    
    # Learning rate schedule
    lr_schedule = ExponentialDecay(
        initial_learning_rate=initial_learning_rate,
        decay_steps=10000,
        decay_rate=0.7,
        staircase=True)
    
    # Create and compile the model
    model = Model(inputs=input_layer, outputs=output)
    optimizer = Adam(learning_rate=lr_schedule)
    
    model.compile(optimizer=optimizer, loss="mean_absolute_error")
    
    return model

现将 [Optiver Trading Close 仓库] 放入您面前,请您期待后续内容中我会同步全部获奖代码。


在这里插入图片描述

全部评论 (0)

还没有任何评论哟~