5e191b11dbd4bdc26bda94bcf17de6fc.png

写在前面

下面这篇文章介绍了Kaggle中,关于金融市场价格预测比赛(Jane Street Market Prediction)中的冠军方案。该获胜方案采用了一个Autoencoder with MLP组成。

1

竞赛背景

5b6dd85875287a5cb3d64140c7196af9.png

    "低买高卖"。这听起来很容易....

    在现实中,交易获利一直是一个难以解决的问题,在今天快速流动和复杂的金融市场中更是如此。电子交易允许在几分之一秒内发生数以千计的交易,从而产生了几乎无限的机会,有可能发现并利用实时的价格差异。

    在一个完全有效的市场中,买家和卖家将拥有做出理性交易决定所需的所有机构和信息。因此,产品将始终保持其 "公平价值",永远不会被低估或定价过高。然而,金融市场在现实世界中并非完全有效。

    制定交易策略来识别和利用无效市场是具有挑战性的。即使一个策略现在是有利可图的,它在未来也不一定是有利可图的,而且市场的波动性使得我们无法确定地预测任何特定交易的盈利能力。因此,要区分好运气和做出好的交易决定可能很困难。

    在这项挑战的前三个月,你将建立自己的量化交易模型,利用全球主要证券交易所的市场数据实现收益最大化。接下来,你将根据未来的市场回报测试你的模型的预测性,并在排行榜上获得反馈。你的挑战将是利用你所掌握的历史数据、数学工具和技术工具,创建一个尽可能接近确定性的模型。你将会看到一些潜在的交易机会,你的模型必须选择是接受还是拒绝。一般来说,如果一个人能够产生一个高预测性的模型,选择正确的交易来执行,他们也将在发送市场信号方面发挥重要作用,推动价格接近 "公平 "的价值。也就是说,一个更好的模型将意味着市场在未来会更有效。然而,开发好的模型将具有挑战性,原因有很多,包括信噪比非常低,潜在的冗余性,强烈的特征相关性,以及难以提出适当的数学公式。

    Jane Street已经花了几十年时间来开发他们自己的交易模型和机器学习解决方案,以识别有利可图的机会,并迅速决定是否执行交易。这些模型帮助Jane Street每天在全球200个交易场所交易成千上万的金融产品。

诚然,这一挑战远远过度简化了Jane Street每天处理的定量问题的深度,而且Jane Street对其现有交易模型在这一特定问题上的表现感到满意。然而,没有什么比一个好的谜题更重要的了,希望这个挑战可以作为一个有趣的介绍,让人们了解Jane Street每天可能解决的数据科学问题的类型。

2

数据描述

训练数据:训练数据集包含一个匿名的特征集,类似特征{0...129},代表真实的股票市场数据。数据集中的每一行都代表一个交易机会,你将为其预测一个action值:1表示进行交易,0表示不进行交易。每个交易都有一个相关的weight和resp,它们共同代表了交易的回报。日期列是一个整数,代表交易日,而ts_id代表一个时间排序。除了匿名的特征值之外,在features.csv中还为你提供了关于特征的元数据。

测试数据:在比赛的模型训练阶段,这个看不见的测试集由大约100万行历史数据组成。在实时预测阶段,测试集将使用定期更新的实时市场数据。

评估方式:竞赛的评估是以回报分数来评估的。其中,测试集中的每一行代表一个交易机会,你将预测一个action值,1表示做交易,0表示不做交易。每笔交易j都有一个相关的weight和resp,代表一个回报。

其中,对于第i个交易日,我们定义:

b7d7001f681d0a50daee80b8468801e9.png

0e464c93254622e0509e2897c461def8.png

最后的评分表示为:

ded59be317bb7bbf150795f3a729b13b.png

3

模型介绍

模型整体采用了AutoEncoder以及MLP的架构,整体框架如下图所示:

5326855d34d73bf174558da95b090a56.png

其中,Autoencoder部分采用了去噪自编码器(Denoise Autoencoder),即在输入数据进入Encoder之前,先加入高斯噪声,这样起到数据增强的作用,有助于缓解过拟合,同时也可以提高特征的表示能力。自编码器的Loss包括两个部分,一部分是MSE Loss,用于重构数据;另一部分是经过一个分类器模块进行多分类任务,用来实现action的分类,保证Encoder学习得到的特征具有跟交易动作相关的特性。MLP部分的输入包括两个部分,即原始数据输入与Encoder的编码结果,多层MLP得到的结果用于最终交易动作的分类。

这部分的实现代码如下,完整源码可以去该notebook下获取:

https://www.kaggle.com/code/gogo827jz/jane-street-supervised-autoencoder-mlp/notebook?scriptVersionId=73762661

def create_ae_mlp(num_columns, num_labels, hidden_units, dropout_rates, ls = 1e-2, lr = 1e-3):
    
    inp = tf.keras.layers.Input(shape = (num_columns, ))
    x0 = tf.keras.layers.BatchNormalization()(inp)
    
    encoder = tf.keras.layers.GaussianNoise(dropout_rates[0])(x0)
    encoder = tf.keras.layers.Dense(hidden_units[0])(encoder)
    encoder = tf.keras.layers.BatchNormalization()(encoder)
    encoder = tf.keras.layers.Activation('swish')(encoder)
    
    decoder = tf.keras.layers.Dropout(dropout_rates[1])(encoder)
    decoder = tf.keras.layers.Dense(num_columns, name = 'decoder')(decoder)


    x_ae = tf.keras.layers.Dense(hidden_units[1])(decoder)
    x_ae = tf.keras.layers.BatchNormalization()(x_ae)
    x_ae = tf.keras.layers.Activation('swish')(x_ae)
    x_ae = tf.keras.layers.Dropout(dropout_rates[2])(x_ae)


    out_ae = tf.keras.layers.Dense(num_labels, activation = 'sigmoid', name = 'ae_action')(x_ae)
    
    x = tf.keras.layers.Concatenate()([x0, encoder])
    x = tf.keras.layers.BatchNormalization()(x)
    x = tf.keras.layers.Dropout(dropout_rates[3])(x)
    
    for i in range(2, len(hidden_units)):
        x = tf.keras.layers.Dense(hidden_units[i])(x)
        x = tf.keras.layers.BatchNormalization()(x)
        x = tf.keras.layers.Activation('swish')(x)
        x = tf.keras.layers.Dropout(dropout_rates[i + 2])(x)
        
    out = tf.keras.layers.Dense(num_labels, activation = 'sigmoid', name = 'action')(x)
    
    model = tf.keras.models.Model(inputs = inp, outputs = [decoder, out_ae, out])
    model.compile(optimizer = tf.keras.optimizers.Adam(learning_rate = lr),
                  loss = {'decoder': tf.keras.losses.MeanSquaredError(), 
                          'ae_action': tf.keras.losses.BinaryCrossentropy(label_smoothing = ls),
                          'action': tf.keras.losses.BinaryCrossentropy(label_smoothing = ls), 
                         },
                  metrics = {'decoder': tf.keras.metrics.MeanAbsoluteError(name = 'MAE'), 
                             'ae_action': tf.keras.metrics.AUC(name = 'AUC'), 
                             'action': tf.keras.metrics.AUC(name = 'AUC'), 
                            }, 
                 )
    
    return model

模型训练的时候采用了PurgedGroupTimeSeriesSplit方式对训练数据进行划分,它可以保证不会有未来数据的泄露,同时也可以采用n-folds的方式进行交叉验证,实验时作者采用了5-folds的方式。

if not TEST:
    scores = []
    batch_size = 4096
    gkf = PurgedGroupTimeSeriesSplit(n_splits = n_splits, group_gap = group_gap)
    for fold, (tr, te) in enumerate(gkf.split(train['action'].values, train['action'].values, train['date'].values)):
        ckp_path = f'JSModel_{fold}.hdf5'
        model = create_ae_mlp(**params)
        ckp = ModelCheckpoint(ckp_path, monitor = 'val_action_AUC', verbose = 0, 
                              save_best_only = True, save_weights_only = True, mode = 'max')
        es = EarlyStopping(monitor = 'val_action_AUC', min_delta = 1e-4, patience = 10, mode = 'max', 
                           baseline = None, restore_best_weights = True, verbose = 0)
        history = model.fit(X[tr], [X[tr], y[tr], y[tr]], validation_data = (X[te], [X[te], y[te], y[te]]), 
                            sample_weight = sw[tr], 
                            epochs = 100, batch_size = batch_size, callbacks = [ckp, es], verbose = 0)
        hist = pd.DataFrame(history.history)
        score = hist['val_action_AUC'].max()
        print(f'Fold {fold} ROC AUC:\t', score)
        scores.append(score)


        K.clear_session()
        del model
        rubbish = gc.collect()
    
    print('Weighted Average CV Score:', weighted_average(scores))

除此之外,作者还采用了一些其他tricks,如Early-Stop、BatchNormalization以及超参数搜索等,另外,自编码器的激活函数用到了swish,而不是relu或者leaky-relu,不过这里具作者所言,采用哪个激活函数区别不大。

参考文献:

https://www.kaggle.com/competitions/jane-street-market-prediction/data

https://www.kaggle.com/code/gogo827jz/jane-street-supervised-autoencoder-mlp/data?scriptVersionId=73762661&select=JSModel_0.hdf5

bc2a884f78c67ec40d3ed9916cd3cbb3.jpeg

了解更多人工智能与
量化金融知识

<-请扫码关注

让我知道你在看

5fbf3c199dfb797ccdfce3ba6fc6b7d4.gif

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐