【CNN-LSTM股票预测模型实现(Python)】

CNN-LSTM股票预测模型实现(Python)

下面是结合CNN和LSTM的混合模型来预测股票价格走势。这个模型使用技术指标作为特征,并采用多变量时间序列预测方法。

1. 数据准备与预处理

首先安装必要的库:

pip install yfinance pandas numpy matplotlib tensorflow ta scikit-learn

1.1 获取股票数据和技术指标

import yfinance as yf
import pandas as pd
import numpy as np
import ta
import matplotlib.pyplot as plt
from sklearn.preprocessing import MinMaxScaler

# 下载股票数据
def download_stock_data(ticker, start_date, end_date):
    data = yf.download(ticker, start=start_date, end=end_date)
    return data

# 计算技术指标
def add_technical_indicators(df):
    # 动量指标
    df['rsi'] = ta.momentum.RSIIndicator(df['Close'], window=14).rsi()
    df['macd'] = ta.trend.MACD(df['Close'], window_slow=26, window_fast=12).macd()
    
    # 趋势指标
    df['ema_20'] = ta.trend.EMAIndicator(df['Close'], window=20).ema_indicator()
    df['ema_50'] = ta.trend.EMAIndicator(df['Close'], window=50).ema_indicator()
    
    # 波动率指标
    df['atr'] = ta.volatility.AverageTrueRange(
        df['High'], df['Low'], df['Close'], window=14).average_true_range()
    
    # 成交量指标
    df['obv'] = ta.volume.OnBalanceVolumeIndicator(
        df['Close'], df['Volume']).on_balance_volume()
    
    return df

# 数据预处理
def preprocess_data(df, look_back=60, test_size=0.2):
    # 选择特征列
    feature_columns = ['Close', 'rsi', 'macd', 'ema_20', 'ema_50', 'atr', 'obv']
    df = df[feature_columns]
    
    # 填充缺失值
    df = df.fillna(method='bfill')
    
    # 归一化
    scaler = MinMaxScaler(feature_range=(0, 1))
    scaled_data = scaler.fit_transform(df)
    
    # 创建时间序列数据集
    X, y = [], []
    for i in range(look_back, len(scaled_data)):
        X.append(scaled_data[i-look_back:i, :])
        y.append(scaled_data[i, 0])  # 只预测Close价格
    
    X, y = np.array(X), np.array(y)
    
    # 划分训练集和测试集
    split = int((1 - test_size) * len(X))
    X_train, X_test = X[:split], X[split:]
    y_train, y_test = y[:split], y[split:]
    
    return X_train, X_test, y_train, y_test, scaler

# 主流程
ticker = 'AAPL'
start_date = '2015-01-01'
end_date = '2023-01-01'

# 获取并处理数据
stock_data = download_stock_data(ticker, start_date, end_date)
stock_data = add_technical_indicators(stock_data)
X_train, X_test, y_train, y_test, scaler = preprocess_data(stock_data)

print(f"训练集形状: {X_train.shape}, 测试集形状: {X_test.shape}")

2. 构建CNN-LSTM模型

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense, Dropout, Flatten
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.callbacks import EarlyStopping

def build_cnn_lstm_model(input_shape):
    model = Sequential()
    
    # CNN部分 - 提取局部特征
    model.add(Conv1D(filters=64, kernel_size=3, activation='relu', 
                    input_shape=input_shape))
    model.add(MaxPooling1D(pool_size=2))
    model.add(Dropout(0.2))
    
    model.add(Conv1D(filters=128, kernel_size=3, activation='relu'))
    model.add(MaxPooling1D(pool_size=2))
    model.add(Dropout(0.2))
    
    # LSTM部分 - 捕捉时间依赖
    model.add(LSTM(units=100, return_sequences=True))
    model.add(Dropout(0.2))
    
    model.add(LSTM(units=100))
    model.add(Dropout(0.2))
    
    # 全连接层
    model.add(Dense(units=50, activation='relu'))
    model.add(Dense(units=1))
    
    # 编译模型
    optimizer = Adam(learning_rate=0.001)
    model.compile(optimizer=optimizer, loss='mean_squared_error')
    
    return model

# 获取输入形状
n_timesteps, n_features = X_train.shape[1], X_train.shape[2]
model = build_cnn_lstm_model((n_timesteps, n_features))
model.summary()

# 训练模型
early_stopping = EarlyStopping(monitor='val_loss', patience=10, restore_best_weights=True)
history = model.fit(
    X_train, y_train,
    epochs=100,
    batch_size=32,
    validation_data=(X_test, y_test),
    callbacks=[early_stopping],
    verbose=1)

# 绘制训练曲线
plt.figure(figsize=(12, 6))
plt.plot(history.history['loss'], label='Train Loss')
plt.plot(history.history['val_loss'], label='Validation Loss')
plt.title('Model Loss Progression')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend()
plt.show()

3. 模型评估与预测

# 预测
y_pred = model.predict(X_test)

# 反归一化
y_test_actual = scaler.inverse_transform(np.concatenate((
    y_test.reshape(-1, 1), 
    np.zeros((len(y_test), X_test.shape[2]-1)), axis=1))[:, 0]
y_pred_actual = scaler.inverse_transform(np.concatenate((
    y_pred.reshape(-1, 1), 
    np.zeros((len(y_pred), X_test.shape[2]-1)), axis=1))[:, 0]

# 计算评估指标
from sklearn.metrics import mean_absolute_error, mean_squared_error

def calculate_metrics(y_true, y_pred):
    mae = mean_absolute_error(y_true, y_pred)
    mse = mean_squared_error(y_true, y_pred)
    rmse = np.sqrt(mse)
    mape = np.mean(np.abs((y_true - y_pred) / y_true)) * 100
    
    print(f"MAE: {mae:.2f}")
    print(f"MSE: {mse:.2f}")
    print(f"RMSE: {rmse:.2f}")
    print(f"MAPE: {mape:.2f}%")
    
    return mae, mse, rmse, mape

calculate_metrics(y_test_actual, y_pred_actual)

# 可视化预测结果
plt.figure(figsize=(14, 7))
plt.plot(y_test_actual, label='Actual Price', color='blue')
plt.plot(y_pred_actual, label='Predicted Price', color='red', alpha=0.7)
plt.title('Stock Price Prediction')
plt.xlabel('Time')
plt.ylabel('Price')
plt.legend()
plt.show()

# 预测未来n天
def predict_future(model, last_sequence, scaler, days_to_predict=5):
    future_predictions = []
    current_sequence = last_sequence.copy()
    
    for _ in range(days_to_predict):
        # 预测下一天
        next_pred = model.predict(current_sequence.reshape(1, n_timesteps, n_features))
        
        # 保存预测结果
        next_pred_full = np.zeros((1, n_features))
        next_pred_full[0, 0] = next_pred[0, 0]
        future_predictions.append(next_pred_full)
        
        # 更新序列
        current_sequence = np.roll(current_sequence, -1, axis=0)
        current_sequence[-1] = next_pred_full
    
    # 反归一化
    future_predictions = np.array(future_predictions).reshape(-1, n_features)
    future_prices = scaler.inverse_transform(future_predictions)[:, 0]
    
    return future_prices

# 使用最后一段数据作为初始序列
last_sequence = X_test[-1]
future_prices = predict_future(model, last_sequence, scaler, days_to_predict=5)
print(f"未来5天的预测价格: {future_prices}")

4. 模型改进建议

特征工程优化

添加更多技术指标(如布林带、KDJ等)

加入基本面数据(市盈率、财报数据等)

考虑市场情绪指标(新闻情感分析)

模型架构改进

# 更复杂的混合架构示例
def build_advanced_model(input_shape):
    input_layer = Input(shape=input_shape)
    
    # CNN分支
    cnn = Conv1D(64, 3, activation='relu')(input_layer)
    cnn = MaxPooling1D(2)(cnn)
    cnn = Conv1D(128, 3, activation='relu')(cnn)
    cnn = GlobalMaxPooling1D()(cnn)
    
    # LSTM分支
    lstm = LSTM(100, return_sequences=True)(input_layer)
    lstm = LSTM(100)(lstm)
    
    # 合并
    merged = concatenate([cnn, lstm])
    merged = Dense(100, activation='relu')(merged)
    output = Dense(1)(merged)
    
    model = Model(inputs=input_layer, outputs=output)
    model.compile(optimizer=Adam(0.001), loss='mse')
    return model

交易策略整合:

将预测结果与风险管理规则结合

添加仓位大小控制

设置止损止盈阈值

回测系统:

# 简易回测框架
def backtest(predictions, actual_prices, initial_capital=10000):
    positions = []
    capital = initial_capital
    
    for i in range(1, len(predictions)):
        if predictions[i] > actual_prices[i-1]:  # 预测上涨
            shares = capital // actual_prices[i]
            capital -= shares * actual_prices[i]
            positions.append(shares)
        else:  # 预测下跌
            if positions:
                capital += positions.pop() * actual_prices[i]
    
    # 清算剩余头寸
    if positions:
        capital += positions[-1] * actual_prices[-1]
    
    return capital

5. 注意事项

市场不确定性:股票市场受众多不可预测因素影响,模型仅作为辅助工具

过拟合风险:使用交叉验证和正则化技术防止过拟合

实时数据:生产环境需要接入实时数据流

交易成本:实际交易需考虑手续费、滑点等成本

这个CNN-LSTM模型提供了股票预测的基础框架,你可以进一步优化特征选择、模型结构和超参数来提升性能。记得在实际交易前进行充分的回测和模拟交易验证。

CNN-LSTM-Attention预测模型是一种结合了卷积神经网络(CNN)、长短期记忆网络(LSTM)和注意力机制(Attention)的深度学习模型。该模型主要用于处理时间序列数据,能够捕捉数据的空间和时间特征,并通过注意力机制对重要信息进行加权处理,从而提高预测精度。 ### 模型结构 1. **卷积神经网络(CNN)**:用于提取输入数据的局部特征。 2. **长短期记忆网络(LSTM)**:用于处理时间序列数据,捕捉时间依赖性。 3. **注意力机制(Attention)**:用于对LSTM输出的重要信息进行加权处理,提高模型对关键信息的关注度。 ### Python实现代码 以下是使用Keras框架实现CNN-LSTM-Attention预测模型的示例代码: ```python import numpy as np from keras.models import Model from keras.layers import Input, Dense, Conv1D, MaxPooling1D, LSTM, Attention, Flatten # 生成示例数据 data = np.random.rand(1000, 100, 10) # (样本数, 时间步长, 特征数) labels = np.random.rand(1000, 1) # 定义模型输入 inputs = Input(shape=(100, 10)) # CNN层 x = Conv1D(filters=64, kernel_size=3, activation='relu')(inputs) x = MaxPooling1D(pool_size=2)(x) x = Flatten()(x) # LSTM层 x = LSTM(64, return_sequences=True)(x) # Attention层 x = Attention()([x, x]) # 全连接层 x = Dense(64, activation='relu')(x) outputs = Dense(1, activation='linear')(x) # 定义模型 model = Model(inputs=inputs, outputs=outputs) # 编译模型 model.compile(optimizer='adam', loss='mean_squared_error') # 训练模型 model.fit(data, labels, epochs=10, batch_size=32) ``` ### 代码说明 1. **数据生成**:生成示例数据,包括输入数据`data`和标签`labels`。 2. **模型定义**: - 输入层:定义输入数据的形状。 - CNN层:使用一维卷积层提取局部特征,并进行最大池化。 - LSTM层:处理时间序列数据,捕捉时间依赖性。 - 注意力机制:使用注意力层对LSTM输出进行加权处理。 - 全连接层:使用全连接层进行最终的预测。 3. **模型编译**:使用Adam优化器和均方误差损失函数进行模型编译。 4. **模型训练**:使用生成的数据进行模型训练。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值