作者:老余捞鱼
原创不易,转载请标明出处及原作者。
写在前面的话:
传统的验证指标(如 RMSE、MSE 或分位数损失)主要用于衡量预测中的平均误差幅度。然而,在训练用于股票市场预测的深度学习模型时,它们在提供对交易风险和回报的有意义的见解方面存在不足。在预测股票市场时,它们没有清楚地说明所涉及的时间或波动性,它们不适合交易者的需求。这就是为什么在深度学习模型中开发用于股票预测的自定义验证指标变得很重要的原因。
以下是本文容的快速摘要:
- 开发自定义验证指标的重要性 — 为什么标准指标达不到要求,以及创建适合股票市场预测的定制验证指标的重要性
- 实施指南 — 有关实施自定义验证指标的详细分步说明。我们将使用 NeuralForecast 来实现该指标
- 训练模型 — 配置模型、准备数据并使用指标训练模型以进行股票市场预测。我们将使用 NeuralForecast 中的 Temporal Fusion Transformer (TFT) 实现
一、为什么要使用自定义验证指标?
在机器学习中,不同的训练损失函数和验证指标具有独特的用途。这种区别有助于我们捕捉学习过程的细节和模型的实际使用情况。
1.1 培训损失的作用
考虑一个分类任务。在训练过程中,我们经常使用交叉熵损失函数。为什么?因为交叉熵损失在比较类的预测概率分布与实际分布时非常有效。这种比较对于模型有效地从数据中学习至关重要。
但是为什么我们不能使用 F1 分数或准确性之类的东西进行训练呢?原因在于对可区分性的需要。深度学习中的训练损失函数必须是可微分的,以便优化算法通过梯度下降来调整模型的权重。像 F1-Score 这样的指标虽然非常适合评估最终表现,但无法区分。
1.2 验证指标的重要性
在验证过程中,我们重点关注模型在实际场景中的表现,在这些场景中,F1 分数等指标变得很重要。F1 分数对于分类任务特别有用,因为它同时考虑了精确度和召回率,从而提供了模型性能的平衡视图,尤其是在处理不平衡数据集的情况下。此外,与交叉熵损失相比,F1 分数更易于人类阅读和直观,因为它直接反映了模型正确分类阳性实例的能力,同时最大限度地减少假阳性和假阴性。让我们看一个使用垃圾邮件分类任务的示例。假设我们有一个二元分类任务来检测电子邮件是垃圾邮件(正类)还是非垃圾邮件(负类)。为简单起见,假设在测试数据集上评估模型后,我们有以下混淆矩阵:
从混淆矩阵中,我们计算出:
- 误报 (FP):5(电子邮件被错误地识别为垃圾邮件)
- 漏报 (FN):10 (垃圾邮件被错误地识别为非垃圾邮件)
使用以下值:
因此,F1 分数为:
这个 84% 的 F1 分数为模型的准确性提供了一个清晰、易懂的衡量标准。它突出了模型预测中精确度和召回率之间的平衡。
1.3 股市预测呢?
拥有自定义验证指标也适用于股票市场预测。对于多个时间序列问题,使用 MSE、RMSE 和分位数损失作为验证指标是完全可以接受的。它们提供了一种可靠的方法来评估预测模型的整体准确性。
但是,对于日内交易,使用均方误差 (MSE) 和均方根误差 (RMSE) 等指标可能会有问题。它们的信息量较少,也更难解释交易决策。这些指标主要用于衡量预测中的平均误差幅度,但它们并不能清楚地了解交易的时间或波动性。日内交易者对其交易的风险/回报更感兴趣。因此,虽然 RMSE 或 MSE 可用于训练,但夏普比率或索蒂诺比率等验证指标更相关。
例如,RMSE 可以最小化预测股票价格和实际股票价格之间的差异,但与此指标相关的交易没有风险或回报。相比之下,夏普比率既考虑了回报又考虑了风险,提供了更直观的交易表现衡量标准。如果模型预测高回报但风险高,交易者可能更喜欢略低的回报和显着降低的风险,夏普比率会强调这一点。
通过NeuralForecast的时间融合转换器(TFT)模型,并在NeuralForecast框架中创建自定义验证指标,我们可以确保我们的模型符合交易者的需求。这种方法有助于选择具有业务代表性的验证指标,使模型在股票预测中更加实用。
二、用于训练和测试模型的配置
我们几乎没有对 TFT 模型进行特征工程,也没有进行降维、交叉验证或超参数优化。主要目标是展示用于股票预测的自定义验证指标。
2.1 使用的数据
为了保持模型的简单性,我们将只关注一个单变量时间序列:SPY(SPDR S&P 500 ETF Trust)的每日回报率。该模型使用 2005 年至 2024 年的历史数据进行训练,涵盖训练期和测试期。我们使用每天的开盘价和收盘价来计算每日回报。这为模型增加了一层真实感。日内交易者可能会在早上开仓,并在一天结束时平仓。为简单起见,我们在初始模型中省略了佣金和滑点等因素,但这些因素可以很容易地纳入。
预测回报使我们能够处理稳态数据。回报通常是静止的——或者至少是微弱的静止——与价格不同,价格是非静止的。此外,虽然预测价格可能与策略取决于未来价格的期权交易者有关,但对于日内交易者来说,重点主要是资产可能产生的潜在回报,而不是其价格。仅仅知道价格,而没有额外的背景信息,如历史价格,对交易者来说几乎没有价值。
此外,我们的模型还结合了每日外生变量,例如 VIX(波动率指数),即 5 年盈亏平衡通货膨胀率,以提高我们的模型性能。
2.2 配置
下面是用于训练和测试模型的 YAML 配置。
start_date :'2005-07-01'
end_date :'2024-05-23'
max_missing_data :0.02
min_nb_trades :60
train_test_split : [0.9, 0.10]
val_proportion_size :0.15
output :
-source :'yahoo'
data :
-'SPY'
historic_variables:
-source:'fred'
data:
-'T5YIE'
-'T10YIE'
-'T10Y3M'
-'DGS10'
-'DGS2'
-'DTB3'
-'DEXUSNZ'
-'VIXCLS'
-'T10Y2Y'
-'NASDAQCOM'
-'DCOILWTICO'
-source:'yahoo'
data:
-"GC=F"
-'MSFT'
-'GOOGL'
-'AAPL'
-'AMZN'
future_variables :
-'day'
-'month'
TFT_parameters:
h:1
input_size:64
max_steps:500
val_check_steps:1
batch_size:32
inference_windows_batch_size:-1
valid_batch_size:2000
learning_rate:0.0005
scaler_type :'robust'
random_seed:42
loss:'HuberMQLoss'
hidden_size:256
n_head:8
dropout:0.1
attn_dropout :0.1
gradient_clip_val:1
other_parameters :
confidence_level:0.6
quantiles : [ 0.05, 0.4, 0.5, 0.6, 0.95 ]
callbacks :
EarlyStopping :
monitor :'valid_loss'
patience :20
verbose :True
mode :'min'
ModelCheckPoint :
monitor :'valid_loss'
mode :'min'
save_top_k :1
verbose :True
- 该模型在 2005-07-01 到 2024-05-23(start_date 年和 end_date)期间使用每日交易日进行了训练和测试。
- max_missing_data :0.02 — 任何给定的外生变量允许的缺失数据点的最大百分比。如果超过该值,我们将放弃该功能。
- min_nb_trades :60 — 此变量设置验证和测试期间所需的最小交易数量。由于我们使用分位数的概率,因此有时我们可能不会进行交易。有关更多信息,请参阅下面的部分,为什么要使用最小交易数量?
- train_test_split :[0.9, 0.10] — 数据比例分为训练集 (90%) 和测试集 (10%)。
- val_proportion_size :0.15 — 为验证目的分配的训练数据比例 (15%)。15% * 90% = 总数据集的 13.5%
- 输出: 为了简单起见,我们预测了一个单一的时间序列:SPY(标准普尔500 ETF)。
- historic_variables : 过去的外生变量(每日基础数据),可能会提高模型的性能。为了简单起见,使用的变量数量保持最少,因为模型是在没有 GPU 的本地计算机上训练和测试的。我们专注于最有用的变量。我们肯定可以增加外生变量的数量,并应用特征工程来提高模型性能。
- 圣路易斯联邦储备委员会经济数据(fred)中的一些例子:VIXCLS – VIX,衡量市场波动性的指标,T10Y3M – 10年减去3个月国债固定期限,T5YIE – 5年盈亏平衡通货膨胀率。来自雅虎财经(yahoo):GC=F — 黄金期货每日价格,MSFT — Microsoft股票每日价格。这两个来源都可以免费使用。
- future_variables : 预测时已知的未来外生变量,例如日和月。例如,如果我们认为投资组合经理在每个月底重新平衡他们的投资组合,这可能会影响当时 SPY 的每日回报率。考虑月底(例如,第 1 个月和第 31 天)等变量可以捕捉这些影响,并有助于做出更好的预测。
- TFT_parameters : 有关 TFT 参数和超参数的定义,请参阅此页面。对于大多数超参数,我们使用了 NeuralForecast 提供的默认值。
- h :1 — 预测范围,即模型预测的提前多少步。我们将其设置为 1,因为我们想要表现得像日内交易者。在每天结束时,我们想知道我们是否应该为第二天做多、做空或不做仓。这使得日常决策成为可能。
- input_size :64 — 用作模型输入的过去时间步长数,相当于大约 3 个月的交易日。
- val_check_steps :1 — 训练期间计算验证指标的频率(以步长为单位)。这是非常小的。对于更大的数据集和更复杂的模型(例如更大的hidden_size),它可以增加到 10、50、100,因为计算成本会很高。
- valid_batch_size :2000 —验证期间的批处理大小设置为 2000,以确保在计算验证度量时一次处理所有验证数据。这是因为自定义验证指标的构建方式使我们只需要在一个批处理中传递所有验证数据。稍后会详细介绍。
- scaler_type :’robust’ — 用于在训练迭代期间分别对每个输入窗口的数据进行归一化 (TemporalNorm) 的缩放器类型。在本例中,使用鲁棒定标器,这是用于时间融合转换器 (TFT) 的默认定标器。它对异常值有效,异常值在经济和金融时间序列中很常见。
- loss :’HuberMQLoss’ — 用于训练的损失函数是具有多分位数回归的 Huber 损失。这种方法对异常值很可靠。Quantiles 通过提供某些结果的概率而不仅仅是点预测,提供了更现实的视角,尤其是在时间序列数据中。此外,它还允许使用分位数推断概率。
- gradient_clip_val :1 — 梯度剪裁的最大值,以防止梯度爆炸。我们可以通过使用 Tenso