作者:老余捞鱼
原创不易,转载请标明出处及原作者。
写在前面的话:最近我用TCN时间卷积网络预测了标普500指数(SPX)的每日回报率,发现效果远超传统方法。TCN通过因果卷积和膨胀卷积捕捉时间序列的长期依赖关系,结合残差连接提升模型性能。这篇文章将带你从数据准备到模型训练,一步步实现金融预测的AI实战。
一、什么是时序卷积网络(TCN)?
时序卷积网络(Temporal Convolutional Network, TCN)是一种用于处理序列数据的深度学习模型。与传统的循环神经网络(RNN)不同,TCN利用卷积操作来捕捉时间序列中的依赖关系。TCN通过因果卷积和扩张卷积的组合,能够有效地处理长序列数据,并且在许多任务中表现出色,如时间序列预测、语音处理和自然语言处理等。
1.1 TCN的基本原理
TCN的核心思想是使用卷积层来替代RNN中的递归结构。其主要特点包括:
- 因果卷积:确保当前时刻的输出仅依赖于当前及之前的输入,避免未来信息的泄露。
- 扩张卷积:通过在卷积核之间引入间隔,使得网络能够在不增加计算复杂度的情况下,捕捉更长范围的依赖关系。
- 残差连接:通过引入残差连接,TCN能够更好地训练深层网络,减轻梯度消失的问题。
上为TCN的简单架构示意图。
1.2 TCN的优点
- 并行计算:与RNN不同,TCN的卷积操作可以并行计算,显著提高训练速度。
- 长距离依赖:扩张卷积使得TCN能够有效捕捉长距离的时间依赖关系。
- 灵活性:TCN可以轻松调整卷积核的大小和扩张因子,以适应不同的序列长度和特征。
1.3 TCN的应用场景
TCN在多个领域得到了广泛应用,包括但不限于:
- 时间序列预测:如股市预测、气象预测等。
- 语音识别:处理音频信号中的时间特征。
- 自然语言处理:用于文本生成和情感分析等任务。
时序卷积网络(TCN)是一种强大的序列建模工具,凭借其独特的卷积结构和高效的训练方式,在处理时间序列数据方面展现了优越的性能。随着深度学习技术的不断发展,TCN有望在更多应用场景中发挥重要作用。
二、TCN的应用实例
下面这个实例将基于标普500指数(SPX)过去15年的历史数据进行模型训练。
为了提高模型的稳定性和预测效果,我们选择使用收益序列而非价格序列,因为收益序列具有更好的静态特性。
此外,在特征工程环节,我们还引入了最近10天的波动率和成交量数据作为补充特征,这些数据能够有效捕捉市场动态,从而进一步提升预测的准确性。
2.1 导入库
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from tensorflow.keras import layers, models
import yfinance as yf
numpy
和pandas
用于数据处理。matplotlib.pyplot
用于绘图。StandardScaler
用于特征标准化。train_test_split
用于划分训练集和测试集。tensorflow.keras
用于构建和训练深度学习模型。yfinance
用于从 Yahoo Finance 获取金融数据。
2.2 数据准备
data_spx = yf.download("^GSPC", start="2010-01-01", end="2024-12-01")
price = data_spx['Adj Close']
volume = data_spx['Volume']
使用 yfinance
下载标普500指数(SPX)从2010年1月1日到2024年12月1日的调整后收盘价和成交量数据。
data = pd.DataFrame({
'Price': price,
'Volume': volume
})
将价格和成交量数据存储在一个 DataFrame
中。
data['Return'] = np.log(data['Price'] / data['Price'].shift(1))
计算对数收益率(log returns),即每日价格变化的对数。
rolling_window = 10
data['Volatility'] = data['Return'].rolling(window=rolling_window).std()
计算10天滚动窗口的波动率(volatility),即收益率的滚动标准差。
data['LogVolume'] = np.log(data['Volume'] + 1)
对成交量进行对数变换,以减小数据的尺度差异。
data = data.dropna()
删除由于滚动操作产生的 NaN
值。
2.3 特征和标签准备
features = data[['Return', 'Volatility', 'LogVolume']].values
labels = data['Return'].shift(-10).dropna().values
- 特征包括收益率、波动率和对数成交量。
- 标签是未来10天的收益率。
features = features[:-10]
对齐特征和标签,确保特征和标签的长度一致。
scaler = StandardScaler()
features = scaler.fit_transform(features)
对特征进行标准化处理,使其均值为0,标准差为1。
sequence_length = 30
X, y = [], []
for i in range(len(features) - sequence_length):
X.append(features[i:i + sequence_length])
y.append(labels[i + sequence_length - 1])
X, y = np.array(X), np.array(y)
将特征数据转换为时间序列格式,每个样本包含30个时间步的特征。
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
将数据集划分为训练集和测试集,测试集占20%。
2.4 TCN模型定义
model = models.Sequential([
layers.Input(shape=(sequence_length, X.shape[2])),
layers.Conv1D(filters=64, kernel_size=3, dilation_rate=1, activation='relu'),
layers.Conv1D(filters=64, kernel_size=3, dilation_rate=2, activation='relu'),
layers.GlobalAveragePooling1D(),
layers.Dense(1)
])
- 定义一个简单的TCN模型,包含两个1D卷积层,分别使用不同的膨胀率(dilation rate)。
- 使用全局平均池化层(GlobalAveragePooling1D)将时间维度压缩为单个值。
- 最后是一个全连接层(Dense),输出未来10天的收益率预测。
model.compile(optimizer='adam', loss='mse')
使用Adam优化器和均方误差(MSE)作为损失函数来编译模型。
2.5 模型训练
epochs = 1000
batch_size = 32
history = model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=epochs, batch_size=batch_size)
训练模型,设置1000个epoch,批量大小为32。
2.6 模型评估
y_pred = model.predict(X_test)
使用测试集进行预测。
plt.figure(figsize=(10, 6))
plt.plot(y_test[-50:], label='Actual Returns', alpha=0.7)
plt.plot(y_pred[-50:], label='Predicted Returns', alpha=0.7)
plt.title('Comparison of Actual vs Predicted Returns')
plt.legend()
plt.show()
绘制实际收益率和预测收益率的对比图。
2.7 保存模型和结果
model.save("tcn_model.h5")
将训练好的模型保存为 tcn_model.h5
文件。
model.summary()
打印模型的摘要信息。
下图为TCN 基础预测与 SPX 最近 50 天的实际回报率对比。
这段代码实现了一个基于TCN的模型,用于预测标普500指数未来10天的收益率。代码涵盖了数据获取、预处理、模型构建、训练、评估和保存的完整流程。
全源代码如下:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from tensorflow.keras import layers, models
import yfinance as yf
# === Data Preparation ===
# Simulate example data (replace this with actual SPX data)
#np.random.seed(42)
#n_days = 1000
#price = np.cumprod(1 + np.random.normal(0, 0.01, n_days)) * 1000
#volume = np.random.randint(1e6, 1e7, n_days)
# Step 1: Fetch SPX data
data_spx = yf.download("^GSPC", start="2010-01-01", end="2024-12-01")
price = data_spx['Adj Close']
volume = data_spx['Volume']
# Create a DataFrame
data = pd.DataFrame({
'Price': price,
'Volume': volume
})
# Compute returns (log returns)
data['Return'] = np.log(data['Price'] / data['Price'].shift(1))
# Compute rolling volatility (10-day window)
rolling_window = 10
data['Volatility'] = data['Return'].rolling(window=rolling_window).std()
# Log-transform volume
data['LogVolume'] = np.log(data['Volume'] + 1)
# Drop NaN values caused by rolling operations
data = data.dropna()
# Prepare features and labels
features = data[['Return', 'Volatility', 'LogVolume']].values
labels = data['Return'].shift(-10).dropna().values # Predict 10-day-ahead return
# Align features with labels
features = features[:-10]
# Standardize features
scaler = StandardScaler()
features = scaler.fit_transform(features)
# Reshape features for TCN (samples, timesteps, features)
sequence_length = 30 # Lookback window
X, y = [], []
for i in range(len(features) - sequence_length):
X.append(features[i:i + sequence_length])
y.append(labels[i + sequence_length - 1])
X, y = np.array(X), np.array(y)
# Split into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# === TCN Model Definition ===
# Define the TCN architecture
model = models.Sequential([
layers.Input(shape=(sequence_length, X.shape[2])),
layers.Conv1D(filters=64, kernel_size=3, dilation_rate=1, activation='relu'),
layers.Conv1D(filters=64, kernel_size=3, dilation_rate=2, activation='relu'),
layers.GlobalAveragePooling1D(),
layers.Dense(1) # Single output for next return prediction
])
# Compile the model
model.compile(optimizer='adam', loss='mse')
# === Model Training ===
# Train the model
epochs = 1000
batch_size = 32
history = model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=epochs, batch_size=batch_size)
# === Model Evaluation ===
# Predict on the test set
y_pred = model.predict(X_test)
# Plot actual vs predicted returns
plt.figure(figsize=(10, 6))
plt.plot(y_test[-50:], label='Actual Returns', alpha=0.7)
plt.plot(y_pred[-50:], label='Predicted Returns', alpha=0.7)
plt.title('Comparison of Actual vs Predicted Returns')
plt.legend()
plt.show()
# === Save Model and Results ===
# Save the model
model.save("tcn_model.h5")
# Print summary
model.summary()
三、观点总结
时序卷积网络(TCN)在时间序列预测任务中表现卓越,主要得益于其出色的长程依赖关系建模能力。与传统的递归架构(如LSTM或GRU)不同,TCN采用扩张卷积运算,能够高效捕捉长时间跨度内的时间模式,同时避免了递归模型中常见的梯度消失问题。这种独特的设计使其在处理复杂时间序列数据时更具优势。
- TCN的关键组成部分包括随意卷积(Casual Convolutions)、稀释卷积(Dilated Convolutions)和残差连接(Residual Connection)。
- TCN能够并行处理整个序列,这使得它比RNN更快地训练。
- TCN通过稀释卷积能够捕捉跳跃时间序列,并且能够处理长内存。
- 通过残差连接和无递归,TCN减少了梯度消失等不稳定性问题。
- 在实际应用中,TCN模型使用了SPX指数的历史数据,包括收益率、波动性和成交量,以及如何预测未来10天的回报率。
- TCN在时间序列预测任务中的优越性能,尤其是在处理长期依赖关系和避免梯度消失问题方面有良好表现。
感谢您阅读到最后,希望这篇文章为您带来了新的启发和实用的知识!如果觉得有帮助,请不吝点赞和分享,您的支持是我持续创作的动力。祝您投资顺利,收益长虹!如果对文中内容有任何疑问,欢迎留言,我会尽快回复!
本文内容仅限技术探讨和学习,不构成任何投资建议。