Python采集东方财富网股票数据建立LSTM模型预测
一、数据爬取流程
先来看一下爬取的数据情况,数据共有2522条,11列(即11个字段),包括每日的额开盘价、收盘价、最高价、最低价等等,如下图所示:
数据所在的目标网址是东方财富网行情中心,如下图所示:
打开任意一只股票详情,例如惠天热电,注意看k线图,如图:
打开浏览器开发者工具抓包,向左拉长时间轴,使k线图完全显示,时间轴如下图所示:
在k线图上随意点击一个点,如下图所示:
以5615为关键字在开发者工具中搜索,找到如图所示的数据包,在该数据包上右键,点击复制,点击复制为cURL(bash),然后进入 爬虫黑科技网站,在curl command输入框内粘贴,即可自动生成爬虫代码。如图所示:
经过本人测试,其实不需要cookies,接下来的数据解析也都很基础,这里不再赘述,完整代码附后。同理,可以爬取任意一只股票历年的数据。
二、爬虫完整代码
import csv
import requests
import re
import json
class EastmoneySpider:
def __init__(self):
self.headers = {
'referer': 'https://quote.eastmoney.com/',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36',
}
def send_request(self, params):
response = requests.get('https://push2his.eastmoney.com/api/qt/stock/kline/get', params=params,
headers=self.headers)
data = response.text
left_data = re.search(r'^.*?(?=\()', data).group() # 找到开头到第一个'('的部分
data = re.sub(left_data + '\(', '', data) # 将匹配到的内容加上'('替换成空字符串
data = re.sub('\);', '', data) # 将结尾的');'替换成空字符串
data = json.loads(data) # 用eval将data转换成字典
return data['data']['klines']
def parse_klines_list(self, klines, filename):
with open(f'{filename}.csv', 'a', encoding='utf-8-sig', newline='') as f:
writer = csv.writer(f)
writer.writerow(['日期', '开盘', '收盘', '最高', '最低', '涨跌幅', '涨跌额', '成交量', '成交额', '振幅', '换手率'])
for kline in klines:
infos = kline.split(',')
if 2013 <= int(infos[0].split('-')[0]) <= 2023:
writer.writerow(infos)
def run(self):
params_list = [{
'cb': 'jQuery35107779909500079947_1717585586473',
'secid': '0.000070',
'ut': 'fa5fd1943c7b386f172d6893dbfba10b',
'fields1': 'f1,f2,f3,f4,f5,f6',
'fields2': 'f51,f52,f53,f54,f55,f56,f57,f58,f59,f60,f61',
'klt': '101',
'fqt': '1',
'end': '20500101',
'lmt': '1000000',
'_': '1717585586480']
filename_list = ['000070特信']
for params, filename in zip(params_list, filename_list):
print(f'正在爬取{filename}数据...')
klines = self.send_request(params)
self.parse_klines_list(klines, filename)
if __name__ == '__main__':
EastmoneySpider().run()
三、LSTM模型建模预测
3.1 项目背景
股票市场作为全球金融市场的重要组成部分,其价格变动不仅影响着投资者的收益,也是全球经济运行状况的晴雨表。随着全球化的推进和信息技术的飞速发展,股票市场日益复杂多变,其价格受到众多因素的影响,包括全球经济状况、货币政策、地缘政治事件等。因此,对股票价格进行准确预测,对于投资者而言,具有至关重要的意义。
传统的股票价格预测方法往往基于统计分析或简单的机器学习模型,这些方法在处理复杂的非线性关系和长期依赖关系时存在局限性。而深度学习作为一种强大的机器学习方法,特别是长短期记忆网络(LSTM),在处理时间序列数据方面展现出了卓越的性能。LSTM模型通过其特殊的结构设计,能够有效地捕捉序列数据中的长期依赖关系,这对于预测股票价格这种受多种因素长期影响的市场行为至关重要。
然而,尽管LSTM在股票价格预测方面具有一定的优势,但现有的研究和实践仍面临一些挑战。一方面,股票市场的复杂性和不确定性使得模型的预测精度和稳定性受到影响;另一方面,LSTM模型的参数调优和特征选择也是影响预测效果的关键因素。因此,对LSTM模型进行优化,提高其在股票价格预测中的性能,具有重要的理论价值和实际应用意义。
基于以上背景,本研究旨在通过优化LSTM模型,提高股票价格预测的准确性和稳定性。我们将从模型结构、参数优化、特征选择等方面入手,对LSTM模型进行改进和优化。通过本研究的开展,我们期望能够为投资者提供更加准确、可靠的股票价格预测工具,同时推动深度学习技术在金融时间序列预测领域的进一步发展。
3.2 建模预测流程
本次建模分析任务使用的数据集是A股ST特信(股票代码000070)的数据集。数据集包含了2013年至2023年该股票在每个交易日的开盘价、收盘价、最高价、最低价、涨跌幅、成交量等数据。
首先导入本次实验用到第三方库并加载数据集。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import plotly.express as px
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_absolute_percentage_error
import tensorflow as tf
from keras import Model
from keras.layers import Input, Dense, Dropout
from keras.layers import LSTM
import warnings
warnings.filterwarnings('ignore')
df = pd.read_csv('./01 股票代码和文件/000070ST特信.csv')
df.head()
输出如图所示:
然后通过df.shape
查看数据大小,通过df.info()
查看数据信息以及可以通过df.describe()
查看数据描述性统计。
3.3 数据预处理
由于我们只使用到开盘价、收盘价、日期、最高价、最低价5列,所以我们只保留5列。
df = df[['日期', '开盘', '收盘', '最高', '最低']]
df.head()
日期特征以对象的形式存储在数据帧中。为了提高计算速度,我们将其数据类型转换为datetime,然后按升序对该特征进行排序。
df['日期'] = pd.to_datetime(df['日期'])
df.sort_values(by='日期', ascending=True, inplace=True)
df.reset_index(drop=True, inplace=True)
3.4 数据可视化
fig = px.line(y=df['收盘'], x=df['日期'])
fig.update_traces(line_color='black')
fig.update_layout(xaxis_title="日期",
yaxis_title="收盘",
title={'text': "股票收盘价历史数据", 'y':0.95, 'x':0.5, 'xanchor':'center', 'yanchor':'top'},
plot_bgcolor='rgba(255,223,0,0.8)')
可视化结果如图所示:
3.5 特征工程
将数据分割为训练集和测试集 由于我们不能对时间序列数据中的未来数据进行训练,所以我们不应该对时间序列数据进行随机分割。在时间序列分割中,测试集总是晚于训练集。我们将2023的时间用于测试,其他时间用于训练。
test_size = df[df['日期'].dt.year==2023].shape[0]
test_size
股票价格训练和测试集
plt.figure(figsize=(15, 6), dpi=150)
plt.rcParams['font.sans-serif']=['SimHei'] #解决中文乱码
plt.rcParams['axes.facecolor'] = 'yellow'
plt.rc('axes',edgecolor='white')
plt.plot(df['日期'][:-test_size], df['收盘'][:-test_size], color='black', lw=2)
plt.plot(df['日期'][-test_size:], df['收盘'][-test_size:], color='blue', lw=2)
plt.title('股票训练和测试集', fontsize=15)
plt.xlabel('日期', fontsize=12)
plt.ylabel('收盘价', fontsize=12)
plt.legend(['训练集', '测试集'], loc='upper left', prop={'size': 15})
plt.grid(color='white')
plt.show()
结果如下图所示:
3.6 数据缩放
由于我们的目标是根据其历史数据预测价格,我们使用MinMaxScaler缩放价格以避免密集的计算:
scaler = MinMaxScaler()
scaler.fit(df['收盘'].values.reshape(-1, 1))
重构数据并创建滑动窗口。利用前一个时间步长来预测下一个时间步长称为滑动窗口。这样,时间序列数据就可以表示为监督学习。我们可以通过使用前一个时间步骤作为输入变量,并使用下一个时间步骤作为输出变量来做到这一点。前一个时间步长的数量称为窗口宽度。这里我们将窗口宽度设置为60。因此,X_train和X_test将是包含60个时间戳价格的嵌套列表。y_train和y_test也是股票价格列表,其中包含第二天的股票价格,分别对应X_train和X_test中的每个列表:
window_size = 60
# 训练集
train_data = df['收盘'][:-test_size]
train_data = scaler.transform(train_data.values.reshape(-1, 1))
X_train = []
y_train = []
train_data
for i in range(window_size, len(train_data)):
X_train.append(train_data[i-60:i, 0])
y_train.append(train_data[i, 0])
# 测试集
test_data = df['收盘'][-test_size-60:]
test_data = scaler.transform(test_data.values.reshape(-1, 1))
X_test = []
y_test = []
for i in range(window_size, len(test_data)):
X_test.append(test_data[i-60:i, 0])
y_test.append(test_data[i, 0])
3.7 数据转换
将数据转换为Numpy数组 现在X_train和X_test是嵌套列表(二维列表),y_train是一维列表。我们需要将它们转换为更高维度的numpy数组,这是TensorFlow在训练神经网络时接受的数据格式:
X_train = np.array(X_train)
X_test = np.array(X_test)
y_train = np.array(y_train)
y_test = np.array(y_test)
X_train = np.reshape(X_train, (X_train.shape[0], X_train.shape[1], 1))
X_test = np.reshape(X_test, (X_test.shape[0], X_test.shape[1], 1))
y_train = np.reshape(y_train, (-1,1))
y_test = np.reshape(y_test, (-1,1))
print('X_train Shape: ', X_train.shape)
print('y_train Shape: ', y_train.shape)
print('X_test Shape: ', X_test.shape)
print('y_test Shape: ', y_test.shape)
3.8 模型创建
创建LSTM网络 我们建立了一个LSTM网络,它是一种递归神经网络,旨在解决梯度消失问题:
# 模型定义:
def define_model():
input1 = Input(shape=(window_size,1))
x = LSTM(units = 64, return_sequences=True)(input1)
x = Dropout(0.2)(x)
x = LSTM(units = 64, return_sequences=True)(x)
x = Dropout(0.2)(x)
x = LSTM(units = 64)(x)
x = Dropout(0.2)(x)
x = Dense(32, activation='softmax')(x)
dnn_output = Dense(1)(x)
model = Model(inputs=input1, outputs=[dnn_output])
model.compile(loss='mean_squared_error', optimizer='Nadam')
model.summary()
return model
# 模型训练:
model = define_model()
history = model.fit(X_train, y_train, epochs=150, batch_size=32, validation_split=0.1, verbose=1)
3.9 评价模型
接下来,我们使用MAPE(平均绝对百分比误差)度量来评估我们的时间序列预测:
result = model.evaluate(X_test, y_test)
y_pred = model.predict(X_test)
MAPE = mean_absolute_percentage_error(y_test, y_pred)
Accuracy = 1 - MAPE
print("Test Loss:", result)
print("Test MAPE:", MAPE)
print("Test Accuracy:", Accuracy)
结果如下图:
3.10 可视化结果
将实际和预测的收盘价返回到它们的原始刻度:
y_test_true = scaler.inverse_transform(y_test)
y_test_pred = scaler.inverse_transform(y_pred)
调查模型预测的价格与实际价格的接近程度:
plt.figure(figsize=(15, 6), dpi=150)
plt.rcParams['axes.facecolor'] = 'yellow'
plt.rc('axes',edgecolor='white')
plt.plot(df['日期'].iloc[:-test_size], scaler.inverse_transform(train_data), color='black', lw=2)
plt.plot(df['日期'].iloc[-test_size:], y_test_true, color='blue', lw=2)
plt.plot(df['日期'].iloc[-test_size:], y_test_pred, color='red', lw=2)
plt.title('模型在股票价格上的表现', fontsize=15)
plt.xlabel('日期', fontsize=12)
plt.ylabel('股票价格', fontsize=12)
plt.legend(['训练集', '真实值', '预测值'], loc='upper left', prop={'size': 15})
plt.grid(color='white')
plt.show()
结果如下图所示:
3.11 总结
实验结果表明,LSTM模型在预测股票价格方面展现出了卓越的性能。预测价格与实际价格高度吻合,证明了模型在捕捉股票价格变化趋势方面的有效性。同时,模型在测试数据上取得了较低的损失值和较高的准确率(以1-MAPE衡量),具体数值为模型损失0.0006和模型准确率95.7%,进一步验证了模型的稳定性和可靠性。
通过本次实验,我们可以得出以下结论:
LSTM模型能够充分利用历史数据中的时间序列信息,有效地预测股票价格的未来走势。
模型对于股票价格变化趋势的捕捉能力强,可以为投资者提供有价值的参考信息,帮助他们制定更为精准的投资策略。
本实验所采用的LSTM模型在股票价格预测领域具有广泛的应用前景,可以进一步拓展到其他金融时间序列预测任务中。
需要注意的是,虽然本实验取得了较为理想的预测结果,但金融市场仍然受到众多不可预测因素的影响。因此,在实际应用中,我们需要持续关注市场动态,结合其他分析方法和技术手段,以提高预测精度和稳定性。同时,随着深度学习技术的不断发展,我们可以进一步探索和改进模型结构,以更好地适应复杂多变的金融市场环境。