安装所需的库¶
在运行以下代码之前,请确保已安装所有必要的库。
In [1]:
# 安装所需的库
# %pip install numpy pandas matplotlib scikit-learn tensorflow
示例1:使用多层感知机(MLP)预测股票收益率¶
问题描述¶
在金融市场中,准确预测股票的未来走势是构建成功交易策略的关键。本示例将使用多层感知机(Multilayer Perceptron, MLP)神经网络来预测合成股票数据的日收益率。
多层感知机简介¶
MLP是一种前馈神经网络,由多层神经元组成,包括输入层、一个或多个隐藏层和输出层。每个神经元使用非线性激活函数(如ReLU),使网络能够学习复杂的非线性模式。
模型架构¶
- 输入层:接收多个技术指标作为特征
- 隐藏层:包含多个全连接层,使用ReLU激活函数
- 输出层:预测未来的股票收益率
实现步骤¶
- 生成合成股票历史数据
- 计算技术指标作为特征输入
- 构建和训练MLP模型
- 使用模型预测未来收益率
- 基于预测构建简单交易策略并评估性能
In [2]:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_squared_error, mean_absolute_error
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout
from tensorflow.keras.optimizers import Adam
import warnings
warnings.filterwarnings('ignore')
# 设置随机种子以确保结果可重现
np.random.seed(42)
tf.random.set_seed(42)
# Chinese font settings for matplotlib
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
# 设置中文字体,这里使用文泉驿微米黑
plt.rcParams['font.family'] = ['sans-serif']
plt.rcParams['font.sans-serif'] = ['WenQuanYi Micro Hei', 'SimHei', 'Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题
2025-05-13 09:53:13.760869: I tensorflow/core/util/port.cc:153] oneDNN custom operations are on. You may see slightly different numerical results due to floating-point round-off errors from different computation orders. To turn them off, set the environment variable `TF_ENABLE_ONEDNN_OPTS=0`. 2025-05-13 09:53:13.761456: I external/local_xla/xla/tsl/cuda/cudart_stub.cc:32] Could not find cuda drivers on your machine, GPU will not be used. 2025-05-13 09:53:13.763628: I external/local_xla/xla/tsl/cuda/cudart_stub.cc:32] Could not find cuda drivers on your machine, GPU will not be used. 2025-05-13 09:53:13.769625: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:467] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered WARNING: All log messages before absl::InitializeLog() is called are written to STDERR E0000 00:00:1747101193.779788 1509475 cuda_dnn.cc:8579] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered E0000 00:00:1747101193.782713 1509475 cuda_blas.cc:1407] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered W0000 00:00:1747101193.790339 1509475 computation_placer.cc:177] computation placer already registered. Please check linkage and avoid linking the same target more than once. W0000 00:00:1747101193.790349 1509475 computation_placer.cc:177] computation placer already registered. Please check linkage and avoid linking the same target more than once. W0000 00:00:1747101193.790350 1509475 computation_placer.cc:177] computation placer already registered. Please check linkage and avoid linking the same target more than once. W0000 00:00:1747101193.790351 1509475 computation_placer.cc:177] computation placer already registered. Please check linkage and avoid linking the same target more than once. 2025-05-13 09:53:13.793272: I tensorflow/core/platform/cpu_feature_guard.cc:210] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations. To enable the following instructions: AVX2 AVX_VNNI FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.
In [3]:
# 生成合成股票数据
def generate_synthetic_stock_data(days=2000, volatility=0.01, drift=0.0001, seed=42):
"""
生成具有真实市场特性的合成股票价格数据
参数:
days (int): 生成的交易日数量
volatility (float): 日波动率
drift (float): 日趋势(漂移)
seed (int): 随机种子以确保可重现性
返回:
pandas.DataFrame: 合成股票价格数据
"""
np.random.seed(seed)
# 生成日期序列
end_date = pd.Timestamp.now().normalize()
start_date = end_date - pd.Timedelta(days=days)
dates = pd.date_range(start=start_date, end=end_date, freq='B') # 工作日
# 生成具有漂移和波动性的对数收益率
returns = np.random.normal(loc=drift, scale=volatility, size=len(dates))
# 添加自相关性和波动率聚类效应(ARCH效应)
for i in range(3, len(returns)):
returns[i] += 0.05 * returns[i-1] - 0.02 * returns[i-2] + 0.01 * returns[i-3]
returns[i] *= 1 + 0.2 * abs(returns[i-1])
# 将收益率转换为价格(初始价格为100)
prices = 100 * np.exp(np.cumsum(returns))
# 创建DataFrame
df = pd.DataFrame({
'Open': prices * (1 - volatility/2),
'High': prices * (1 + volatility),
'Low': prices * (1 - volatility),
'Close': prices,
'Volume': np.random.lognormal(mean=15, sigma=1, size=len(dates)) # 随机成交量
}, index=dates)
# 为开盘价、最高价、最低价添加随机性
for i in range(len(df)):
open_price = df.iloc[i]['Open']
close_price = df.iloc[i]['Close']
high_price = max(open_price, close_price) * (1 + np.random.uniform(0, 0.005))
low_price = min(open_price, close_price) * (1 - np.random.uniform(0, 0.005))
df.iloc[i, df.columns.get_loc('High')] = high_price
df.iloc[i, df.columns.get_loc('Low')] = low_price
# 添加市场周期 - 牛市和熊市
regime_changes = np.random.choice(range(100, len(df) - 100), size=4, replace=False)
regime_changes.sort()
for i, change_point in enumerate(regime_changes):
regime_length = np.random.randint(30, 100)
if i % 2 == 0: # 牛市
df.iloc[change_point:change_point+regime_length, df.columns.get_loc('Close')] *= \
np.exp(np.linspace(0, 0.2, regime_length))
else: # 熊市
df.iloc[change_point:change_point+regime_length, df.columns.get_loc('Close')] *= \
np.exp(np.linspace(0, -0.2, regime_length))
# 更新Open、High、Low以保持一致性
for i in range(1, len(df)):
df.iloc[i, df.columns.get_loc('Open')] = df.iloc[i-1, df.columns.get_loc('Close')] * \
(1 + np.random.normal(0, 0.003))
df.iloc[i, df.columns.get_loc('High')] = max(df.iloc[i]['Open'], df.iloc[i]['Close']) * \
(1 + np.random.uniform(0, 0.01))
df.iloc[i, df.columns.get_loc('Low')] = min(df.iloc[i]['Open'], df.iloc[i]['Close']) * \
(1 - np.random.uniform(0, 0.01))
print(f"成功生成{len(df)}条合成交易数据,从{df.index[0].date()}到{df.index[-1].date()}")
return df
In [4]:
# 创建技术指标
def create_features(df):
"""
创建技术指标作为模型特征
参数:
df (pandas.DataFrame): 股票价格数据
返回:
pandas.DataFrame: 包含技术指标的DataFrame
"""
# 计算收益率
df['Return'] = df['Close'].pct_change()
# 计算价格动量指标
df['Return_1'] = df['Return'].shift(1) # 前1天收益率
df['Return_2'] = df['Return'].shift(2) # 前2天收益率
df['Return_3'] = df['Return'].shift(3) # 前3天收益率
df['Return_5'] = df['Return'].shift(5) # 前5天收益率
# 计算移动平均线
df['MA5'] = df['Close'].rolling(window=5).mean() / df['Close'] - 1
df['MA10'] = df['Close'].rolling(window=10).mean() / df['Close'] - 1
df['MA20'] = df['Close'].rolling(window=20).mean() / df['Close'] - 1
df['MA50'] = df['Close'].rolling(window=50).mean() / df['Close'] - 1
# 计算相对强弱指标(RSI)
delta = df['Close'].diff()
gain = delta.where(delta > 0, 0).rolling(window=14).mean()
loss = -delta.where(delta < 0, 0).rolling(window=14).mean()
rs = gain / loss
df['RSI'] = 100 - (100 / (1 + rs))
# 计算布林带
df['BBUp'] = (df['Close'].rolling(window=20).mean() + 2 * df['Close'].rolling(window=20).std()) / df['Close'] - 1
df['BBDown'] = (df['Close'].rolling(window=20).mean() - 2 * df['Close'].rolling(window=20).std()) / df['Close'] - 1
# 计算成交量变化
df['Volume_Change'] = df['Volume'].pct_change()
df['Volume_MA5'] = df['Volume'] / df['Volume'].rolling(window=5).mean() - 1
# 计算波动率
df['Volatility'] = df['Return'].rolling(window=20).std()
# 删除NaN值
df.dropna(inplace=True)
return df
In [5]:
# 构建和训练MLP模型
def build_and_train_model(X_train, y_train, X_val, y_val):
"""
构建并训练MLP模型
参数:
X_train, y_train: 训练数据
X_val, y_val: 验证数据
返回:
训练好的模型和训练历史
"""
# 构建模型架构
model = Sequential([
# 输入层和第一个隐藏层
Dense(64, activation='relu', input_shape=(X_train.shape[1],)),
Dropout(0.2), # 防止过拟合
# 第二个隐藏层
Dense(32, activation='relu'),
Dropout(0.2),
# 输出层 - 预测收益率(回归问题)
Dense(1)
])
# 编译模型
model.compile(
optimizer=Adam(learning_rate=0.001),
loss='mse', # 均方误差损失函数适用于回归问题
metrics=['mae'] # 同时监控平均绝对误差
)
# 打印模型架构
model.summary()
# 训练模型(使用早停法防止过拟合)
history = model.fit(
X_train, y_train,
validation_data=(X_val, y_val),
epochs=100,
batch_size=32,
callbacks=[tf.keras.callbacks.EarlyStopping(patience=10, restore_best_weights=True)],
verbose=1
)
return model, history
In [6]:
# 可视化生成的股票价格数据
def plot_synthetic_data(data, ticker_name="合成股票"):
"""
可视化合成股票数据
参数:
data (pandas.DataFrame): 股票价格数据
ticker_name (str): 股票名称
"""
plt.figure(figsize=(14, 10))
# 绘制价格图
plt.subplot(2, 1, 1)
plt.plot(data.index, data['Close'], label='收盘价')
plt.title(f'{ticker_name}价格走势')
plt.xlabel('日期')
plt.ylabel('价格')
plt.grid(True, alpha=0.3)
plt.legend()
# 绘制成交量图
plt.subplot(2, 1, 2)
plt.bar(data.index, data['Volume'], alpha=0.5, label='成交量')
plt.title(f'{ticker_name}成交量')
plt.xlabel('日期')
plt.ylabel('成交量')
plt.grid(True, alpha=0.3)
plt.legend()
plt.tight_layout()
plt.show()
In [7]:
# 主函数
def main():
# 设置参数
ticker_name = '合成股票'
days = 2000
# 生成合成股票数据
data = generate_synthetic_stock_data(days=days, volatility=0.015, drift=0.0002, seed=42)
# 可视化生成的数据
plot_synthetic_data(data, ticker_name)
# 创建特征
data = create_features(data)
# 定义特征和目标变量
feature_columns = ['Return_1', 'Return_2', 'Return_3', 'Return_5',
'MA5', 'MA10', 'MA20', 'MA50',
'RSI', 'BBUp', 'BBDown',
'Volume_Change', 'Volume_MA5', 'Volatility']
X = data[feature_columns].values
y = data['Return'].values
# 数据标准化
scaler = StandardScaler()
X = scaler.fit_transform(X)
# 划分训练集和测试集 (80% 训练, 20% 测试)
train_size = int(len(X) * 0.8)
X_train, X_test = X[:train_size], X[train_size:]
y_train, y_test = y[:train_size], y[train_size:]
# 进一步划分训练集和验证集
val_size = int(len(X_train) * 0.2)
X_val = X_train[-val_size:]
y_val = y_train[-val_size:]
X_train = X_train[:-val_size]
y_train = y_train[:-val_size]
print(f'训练集大小: {X_train.shape}, 验证集大小: {X_val.shape}, 测试集大小: {X_test.shape}')
# 构建和训练模型
model, history = build_and_train_model(X_train, y_train, X_val, y_val)
# 评估模型
y_pred = model.predict(X_test)
mse = mean_squared_error(y_test, y_pred)
mae = mean_absolute_error(y_test, y_pred)
print(f'测试集MSE: {mse:.6f}')
print(f'测试集MAE: {mae:.6f}')
# 可视化训练历史
plt.figure(figsize=(12, 5))
plt.subplot(1, 2, 1)
plt.plot(history.history['loss'], label='训练损失')
plt.plot(history.history['val_loss'], label='验证损失')
plt.title('损失历史')
plt.xlabel('周期')
plt.ylabel('损失')
plt.legend()
# 可视化预测结果
plt.subplot(1, 2, 2)
plt.scatter(y_test, y_pred, alpha=0.5)
plt.xlabel('实际收益率')
plt.ylabel('预测收益率')
plt.title('预测值与实际值对比')
plt.plot([-0.2, 0.2], [-0.2, 0.2], 'r--') # 对角线
plt.tight_layout()
plt.show()
# 计算预测收益率
test_indices = data.index[train_size:]
test_data = data.loc[test_indices].copy()
test_data['Predicted_Return'] = y_pred
# 制定简单交易策略
# 如果预测收益为正,则做多(1);如果为负,则做空(-1)
test_data['Position'] = np.where(test_data['Predicted_Return'] > 0, 1, -1)
test_data['Strategy_Return'] = test_data['Position'].shift(1) * test_data['Return']
# 计算累积收益
test_data['Cumulative_Market_Return'] = (1 + test_data['Return']).cumprod() - 1
test_data['Cumulative_Strategy_Return'] = (1 + test_data['Strategy_Return']).cumprod() - 1
# 可视化策略收益
plt.figure(figsize=(12, 6))
plt.plot(test_data.index, test_data['Cumulative_Market_Return'], label='买入持有')
plt.plot(test_data.index, test_data['Cumulative_Strategy_Return'], label='MLP策略')
plt.xlabel('日期')
plt.ylabel('累积收益')
plt.title(f'策略表现: {ticker_name}')
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
# 计算年化收益率和夏普比率
days = (test_data.index[-1] - test_data.index[0]).days
annual_factor = 252 / days * len(test_data)
market_return = test_data['Cumulative_Market_Return'].iloc[-1]
strategy_return = test_data['Cumulative_Strategy_Return'].iloc[-1]
market_annual_return = (1 + market_return) ** annual_factor - 1
strategy_annual_return = (1 + strategy_return) ** annual_factor - 1
market_volatility = test_data['Return'].std() * np.sqrt(252)
strategy_volatility = test_data['Strategy_Return'].std() * np.sqrt(252)
market_sharpe = market_annual_return / market_volatility
strategy_sharpe = strategy_annual_return / strategy_volatility
print(f"\n策略表现评估:")
print(f"市场总收益: {market_return:.4f}, 年化收益率: {market_annual_return:.4f}, 夏普比率: {market_sharpe:.4f}")
print(f"策略总收益: {strategy_return:.4f}, 年化收益率: {strategy_annual_return:.4f}, 夏普比率: {strategy_sharpe:.4f}")
# 运行主函数
if __name__ == "__main__":
main()
成功生成1429条合成交易数据,从2019-11-21到2025-05-13
训练集大小: (884, 14), 验证集大小: (220, 14), 测试集大小: (276, 14)
E0000 00:00:1747101196.252710 1509475 cuda_executor.cc:1228] INTERNAL: CUDA Runtime error: Failed call to cudaGetRuntimeVersion: Error loading CUDA libraries. GPU will not be used.: Error loading CUDA libraries. GPU will not be used. W0000 00:00:1747101196.254839 1509475 gpu_device.cc:2341] Cannot dlopen some GPU libraries. Please make sure the missing libraries mentioned above are installed properly if you would like to use GPU. Follow the guide at https://www.tensorflow.org/install/gpu for how to download and setup the required libraries for your platform. Skipping registering GPU devices...
Model: "sequential"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Layer (type) ┃ Output Shape ┃ Param # ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ dense (Dense) │ (None, 64) │ 960 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dropout (Dropout) │ (None, 64) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense_1 (Dense) │ (None, 32) │ 2,080 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dropout_1 (Dropout) │ (None, 32) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense_2 (Dense) │ (None, 1) │ 33 │ └─────────────────────────────────┴────────────────────────┴───────────────┘
Total params: 3,073 (12.00 KB)
Trainable params: 3,073 (12.00 KB)
Non-trainable params: 0 (0.00 B)
Epoch 1/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 1s 5ms/step - loss: 0.1452 - mae: 0.2870 - val_loss: 0.0161 - val_mae: 0.0951 Epoch 2/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 0.0677 - mae: 0.1743 - val_loss: 0.0095 - val_mae: 0.0702 Epoch 3/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 0.0503 - mae: 0.1426 - val_loss: 0.0053 - val_mae: 0.0522 Epoch 4/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 0.0333 - mae: 0.1188 - val_loss: 0.0039 - val_mae: 0.0445 Epoch 5/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 0.0165 - mae: 0.0862 - val_loss: 0.0024 - val_mae: 0.0337 Epoch 6/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 0.0117 - mae: 0.0719 - val_loss: 0.0017 - val_mae: 0.0296 Epoch 7/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 0.0118 - mae: 0.0731 - val_loss: 0.0013 - val_mae: 0.0253 Epoch 8/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 0.0079 - mae: 0.0576 - val_loss: 0.0010 - val_mae: 0.0224 Epoch 9/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 0.0056 - mae: 0.0508 - val_loss: 9.2653e-04 - val_mae: 0.0208 Epoch 10/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 0.0070 - mae: 0.0506 - val_loss: 7.6259e-04 - val_mae: 0.0201 Epoch 11/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 0.0059 - mae: 0.0492 - val_loss: 6.1242e-04 - val_mae: 0.0188 Epoch 12/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 0.0046 - mae: 0.0439 - val_loss: 5.2198e-04 - val_mae: 0.0173 Epoch 13/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 0.0042 - mae: 0.0403 - val_loss: 4.3124e-04 - val_mae: 0.0164 Epoch 14/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 0.0052 - mae: 0.0383 - val_loss: 4.7747e-04 - val_mae: 0.0174 Epoch 15/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 0.0033 - mae: 0.0361 - val_loss: 3.5942e-04 - val_mae: 0.0133 Epoch 16/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 0.0034 - mae: 0.0337 - val_loss: 3.4549e-04 - val_mae: 0.0142 Epoch 17/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 0.0021 - mae: 0.0302 - val_loss: 2.4425e-04 - val_mae: 0.0118 Epoch 18/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 3ms/step - loss: 0.0018 - mae: 0.0270 - val_loss: 2.7498e-04 - val_mae: 0.0116 Epoch 19/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 0.0017 - mae: 0.0263 - val_loss: 2.7879e-04 - val_mae: 0.0113 Epoch 20/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 0.0017 - mae: 0.0242 - val_loss: 2.3859e-04 - val_mae: 0.0108 Epoch 21/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 0.0013 - mae: 0.0221 - val_loss: 2.1520e-04 - val_mae: 0.0106 Epoch 22/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 0.0014 - mae: 0.0227 - val_loss: 2.0103e-04 - val_mae: 0.0102 Epoch 23/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 0.0015 - mae: 0.0237 - val_loss: 1.8616e-04 - val_mae: 0.0101 Epoch 24/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 0.0012 - mae: 0.0214 - val_loss: 1.6555e-04 - val_mae: 0.0097 Epoch 25/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 0.0011 - mae: 0.0206 - val_loss: 1.8218e-04 - val_mae: 0.0097 Epoch 26/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 8.1334e-04 - mae: 0.0180 - val_loss: 1.8235e-04 - val_mae: 0.0097 Epoch 27/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 0.0013 - mae: 0.0192 - val_loss: 1.6904e-04 - val_mae: 0.0094 Epoch 28/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 3ms/step - loss: 0.0013 - mae: 0.0197 - val_loss: 1.5493e-04 - val_mae: 0.0092 Epoch 29/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 8.9257e-04 - mae: 0.0167 - val_loss: 1.4449e-04 - val_mae: 0.0090 Epoch 30/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 9.0972e-04 - mae: 0.0182 - val_loss: 1.3108e-04 - val_mae: 0.0088 Epoch 31/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 5.8535e-04 - mae: 0.0162 - val_loss: 1.2734e-04 - val_mae: 0.0086 Epoch 32/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 7.5554e-04 - mae: 0.0156 - val_loss: 1.2433e-04 - val_mae: 0.0086 Epoch 33/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 7.0459e-04 - mae: 0.0160 - val_loss: 1.2296e-04 - val_mae: 0.0085 Epoch 34/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 7.1500e-04 - mae: 0.0156 - val_loss: 1.2021e-04 - val_mae: 0.0084 Epoch 35/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 5.6236e-04 - mae: 0.0151 - val_loss: 1.1934e-04 - val_mae: 0.0084 Epoch 36/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 5.1310e-04 - mae: 0.0146 - val_loss: 1.1521e-04 - val_mae: 0.0083 Epoch 37/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 3.9984e-04 - mae: 0.0128 - val_loss: 1.1192e-04 - val_mae: 0.0082 Epoch 38/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 3ms/step - loss: 3.7934e-04 - mae: 0.0128 - val_loss: 1.0905e-04 - val_mae: 0.0081 Epoch 39/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 4.3573e-04 - mae: 0.0134 - val_loss: 1.0574e-04 - val_mae: 0.0080 Epoch 40/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 4.2541e-04 - mae: 0.0136 - val_loss: 1.0344e-04 - val_mae: 0.0079 Epoch 41/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 8.3598e-04 - mae: 0.0139 - val_loss: 1.0685e-04 - val_mae: 0.0080 Epoch 42/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 6.0258e-04 - mae: 0.0134 - val_loss: 1.0667e-04 - val_mae: 0.0080 Epoch 43/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 6.7581e-04 - mae: 0.0142 - val_loss: 1.0393e-04 - val_mae: 0.0079 Epoch 44/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 3.8638e-04 - mae: 0.0124 - val_loss: 1.0394e-04 - val_mae: 0.0079 Epoch 45/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 3.7973e-04 - mae: 0.0123 - val_loss: 1.0454e-04 - val_mae: 0.0079 Epoch 46/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 6.7672e-04 - mae: 0.0126 - val_loss: 1.0526e-04 - val_mae: 0.0079 Epoch 47/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 4.2178e-04 - mae: 0.0128 - val_loss: 1.0440e-04 - val_mae: 0.0079 Epoch 48/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 2.9563e-04 - mae: 0.0119 - val_loss: 1.0430e-04 - val_mae: 0.0079 Epoch 49/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 3.6254e-04 - mae: 0.0117 - val_loss: 1.0227e-04 - val_mae: 0.0079 Epoch 50/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 6.3998e-04 - mae: 0.0128 - val_loss: 9.7143e-05 - val_mae: 0.0077 Epoch 51/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 6.6002e-04 - mae: 0.0124 - val_loss: 9.4222e-05 - val_mae: 0.0076 Epoch 52/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 3.9816e-04 - mae: 0.0123 - val_loss: 9.7411e-05 - val_mae: 0.0078 Epoch 53/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 3.9034e-04 - mae: 0.0116 - val_loss: 9.8250e-05 - val_mae: 0.0077 Epoch 54/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 4.4894e-04 - mae: 0.0110 - val_loss: 9.3661e-05 - val_mae: 0.0075 Epoch 55/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 2.7034e-04 - mae: 0.0115 - val_loss: 8.8417e-05 - val_mae: 0.0073 Epoch 56/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 2.7465e-04 - mae: 0.0109 - val_loss: 8.6754e-05 - val_mae: 0.0072 Epoch 57/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 3ms/step - loss: 3.4334e-04 - mae: 0.0111 - val_loss: 9.0415e-05 - val_mae: 0.0073 Epoch 58/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 9.4170e-04 - mae: 0.0110 - val_loss: 9.0224e-05 - val_mae: 0.0072 Epoch 59/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 2.7063e-04 - mae: 0.0113 - val_loss: 9.1404e-05 - val_mae: 0.0067 Epoch 60/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 3.1633e-04 - mae: 0.0126 - val_loss: 9.4119e-05 - val_mae: 0.0072 Epoch 61/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 4.7944e-04 - mae: 0.0126 - val_loss: 8.5940e-05 - val_mae: 0.0069 Epoch 62/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 3.7585e-04 - mae: 0.0120 - val_loss: 8.7295e-05 - val_mae: 0.0071 Epoch 63/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 2.5852e-04 - mae: 0.0105 - val_loss: 8.5502e-05 - val_mae: 0.0069 Epoch 64/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 1.7714e-04 - mae: 0.0098 - val_loss: 8.4334e-05 - val_mae: 0.0069 Epoch 65/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 2.1173e-04 - mae: 0.0104 - val_loss: 8.5586e-05 - val_mae: 0.0070 Epoch 66/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 2.6774e-04 - mae: 0.0100 - val_loss: 8.4834e-05 - val_mae: 0.0070 Epoch 67/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 2.2499e-04 - mae: 0.0105 - val_loss: 8.7676e-05 - val_mae: 0.0072 Epoch 68/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 2.4449e-04 - mae: 0.0104 - val_loss: 8.2481e-05 - val_mae: 0.0069 Epoch 69/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 2.0157e-04 - mae: 0.0098 - val_loss: 7.7257e-05 - val_mae: 0.0066 Epoch 70/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 2.1037e-04 - mae: 0.0100 - val_loss: 7.5940e-05 - val_mae: 0.0066 Epoch 71/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 1.6909e-04 - mae: 0.0095 - val_loss: 7.4266e-05 - val_mae: 0.0065 Epoch 72/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 1.9745e-04 - mae: 0.0102 - val_loss: 7.1814e-05 - val_mae: 0.0064 Epoch 73/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 2.1152e-04 - mae: 0.0100 - val_loss: 7.0770e-05 - val_mae: 0.0063 Epoch 74/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 2.5674e-04 - mae: 0.0102 - val_loss: 7.2387e-05 - val_mae: 0.0064 Epoch 75/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 3ms/step - loss: 1.7843e-04 - mae: 0.0090 - val_loss: 7.0144e-05 - val_mae: 0.0063 Epoch 76/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 2.2376e-04 - mae: 0.0095 - val_loss: 6.6701e-05 - val_mae: 0.0061 Epoch 77/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 1.9767e-04 - mae: 0.0095 - val_loss: 6.5786e-05 - val_mae: 0.0061 Epoch 78/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 1.6978e-04 - mae: 0.0092 - val_loss: 6.3821e-05 - val_mae: 0.0060 Epoch 79/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 1.8320e-04 - mae: 0.0091 - val_loss: 6.0754e-05 - val_mae: 0.0058 Epoch 80/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 1.7384e-04 - mae: 0.0088 - val_loss: 6.5582e-05 - val_mae: 0.0061 Epoch 81/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 1.9279e-04 - mae: 0.0092 - val_loss: 6.4161e-05 - val_mae: 0.0060 Epoch 82/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 1.7418e-04 - mae: 0.0093 - val_loss: 6.3466e-05 - val_mae: 0.0060 Epoch 83/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 1.6630e-04 - mae: 0.0087 - val_loss: 6.2138e-05 - val_mae: 0.0059 Epoch 84/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 3ms/step - loss: 1.6748e-04 - mae: 0.0090 - val_loss: 5.9314e-05 - val_mae: 0.0057 Epoch 85/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 2.3256e-04 - mae: 0.0088 - val_loss: 5.9064e-05 - val_mae: 0.0057 Epoch 86/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 1.6798e-04 - mae: 0.0087 - val_loss: 5.7430e-05 - val_mae: 0.0056 Epoch 87/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 1.6013e-04 - mae: 0.0088 - val_loss: 5.6451e-05 - val_mae: 0.0056 Epoch 88/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 1.7349e-04 - mae: 0.0087 - val_loss: 5.6736e-05 - val_mae: 0.0057 Epoch 89/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 1.3874e-04 - mae: 0.0086 - val_loss: 5.1037e-05 - val_mae: 0.0053 Epoch 90/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 1.7211e-04 - mae: 0.0086 - val_loss: 5.4484e-05 - val_mae: 0.0055 Epoch 91/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 1.3973e-04 - mae: 0.0082 - val_loss: 5.7454e-05 - val_mae: 0.0057 Epoch 92/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 1.4266e-04 - mae: 0.0085 - val_loss: 5.2139e-05 - val_mae: 0.0053 Epoch 93/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 1.1871e-04 - mae: 0.0079 - val_loss: 5.2184e-05 - val_mae: 0.0054 Epoch 94/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 1.4117e-04 - mae: 0.0084 - val_loss: 5.8435e-05 - val_mae: 0.0058 Epoch 95/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 1.4337e-04 - mae: 0.0083 - val_loss: 5.0924e-05 - val_mae: 0.0053 Epoch 96/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 1.5008e-04 - mae: 0.0083 - val_loss: 4.5182e-05 - val_mae: 0.0049 Epoch 97/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 1.2243e-04 - mae: 0.0079 - val_loss: 4.3832e-05 - val_mae: 0.0049 Epoch 98/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 1.4344e-04 - mae: 0.0078 - val_loss: 4.5663e-05 - val_mae: 0.0050 Epoch 99/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 1.5283e-04 - mae: 0.0080 - val_loss: 5.1459e-05 - val_mae: 0.0053 Epoch 100/100 28/28 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - loss: 1.2394e-04 - mae: 0.0077 - val_loss: 4.6202e-05 - val_mae: 0.0050 9/9 ━━━━━━━━━━━━━━━━━━━━ 0s 3ms/step 测试集MSE: 0.000146 测试集MAE: 0.007346
策略表现评估: 市场总收益: 0.2293, 年化收益率: 15803649410701860.0000, 夏普比率: 40487018929765168.0000 策略总收益: -0.0225, 年化收益率: -0.9837, 夏普比率: -2.5163
结果分析与解释¶
在上面的示例中,我们使用MLP模型预测合成股票数据的收益率,并基于预测结果构建了一个简单的交易策略。以下是对结果的解释:
合成数据生成:
- 我们生成了具有真实市场特性的合成股票数据
- 包括波动率聚类、趋势、牛熊市周期等特征
- 这使我们能够在没有实际市场数据的情况下测试模型效果
模型性能:
- MSE和MAE指标显示了模型预测的准确性
- 在模拟的股票市场环境中,低误差已经是很好的结果
预测分析:
- 散点图显示了预测值与实际值的关系
- 理想情况下,点应分布在对角线附近
策略表现:
- 策略收益曲线与买入持有策略的比较
- 年化收益率和夏普比率显示了策略的风险调整后收益
局限性和改进方向¶
- 尽管合成数据模拟了真实市场的一些特性,但仍无法完全捕捉真实市场的复杂性
- MLP对时间序列数据的处理能力有限,没有明确捕捉时间依赖关系
- 简单的做多/做空策略没有考虑交易成本和滑点
- 可以考虑加入更多特征或使用更复杂的网络架构