深度学习在量化交易中的应用¶

简介¶

本笔记本展示了五个深度学习在量化金融领域的实战应用案例:

  1. 使用多层感知机(MLP)预测股票收益率
  2. 使用长短期记忆网络(LSTM)预测金融时间序列波动率
  3. 使用卷积神经网络(CNN)识别金融时间序列模式
  4. 使用生成对抗网络(GAN)生成合成金融时间序列
  5. 使用深度强化学习(DDPG)进行投资组合优化

每个案例都包含详细的实现代码、模型解释和结果可视化。

安装所需的库¶

在运行以下代码之前,请确保已安装所有必要的库。

In [1]:
# 安装所需的库
# %pip install numpy pandas matplotlib scikit-learn tensorflow

示例1:使用多层感知机(MLP)预测股票收益率¶

问题描述¶

在金融市场中,准确预测股票的未来走势是构建成功交易策略的关键。本示例将使用多层感知机(Multilayer Perceptron, MLP)神经网络来预测合成股票数据的日收益率。

多层感知机简介¶

MLP是一种前馈神经网络,由多层神经元组成,包括输入层、一个或多个隐藏层和输出层。每个神经元使用非线性激活函数(如ReLU),使网络能够学习复杂的非线性模式。

模型架构¶

  • 输入层:接收多个技术指标作为特征
  • 隐藏层:包含多个全连接层,使用ReLU激活函数
  • 输出层:预测未来的股票收益率

实现步骤¶

  1. 生成合成股票历史数据
  2. 计算技术指标作为特征输入
  3. 构建和训练MLP模型
  4. 使用模型预测未来收益率
  5. 基于预测构建简单交易策略并评估性能
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
No description has been provided for this image
训练集大小: (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
No description has been provided for this image
No description has been provided for this image
策略表现评估:
市场总收益: 0.2293, 年化收益率: 15803649410701860.0000, 夏普比率: 40487018929765168.0000
策略总收益: -0.0225, 年化收益率: -0.9837, 夏普比率: -2.5163

结果分析与解释¶

在上面的示例中,我们使用MLP模型预测合成股票数据的收益率,并基于预测结果构建了一个简单的交易策略。以下是对结果的解释:

  1. 合成数据生成:

    • 我们生成了具有真实市场特性的合成股票数据
    • 包括波动率聚类、趋势、牛熊市周期等特征
    • 这使我们能够在没有实际市场数据的情况下测试模型效果
  2. 模型性能:

    • MSE和MAE指标显示了模型预测的准确性
    • 在模拟的股票市场环境中,低误差已经是很好的结果
  3. 预测分析:

    • 散点图显示了预测值与实际值的关系
    • 理想情况下,点应分布在对角线附近
  4. 策略表现:

    • 策略收益曲线与买入持有策略的比较
    • 年化收益率和夏普比率显示了策略的风险调整后收益

局限性和改进方向¶

  1. 尽管合成数据模拟了真实市场的一些特性,但仍无法完全捕捉真实市场的复杂性
  2. MLP对时间序列数据的处理能力有限,没有明确捕捉时间依赖关系
  3. 简单的做多/做空策略没有考虑交易成本和滑点
  4. 可以考虑加入更多特征或使用更复杂的网络架构