接下来几期我们将使用机器学习方法帮助我们预测未来股票交易数据的走势。在此之前我们需要对数据进行预处理以供机器学习方法使用。这一期我们将以复权收盘价数据为例,学习如何生成有效的特征数据。
在这个系列中,我们将共同学习如何借助Python这个强大的工具处理金融数据。在正式开始这个系列的学习之前,需要您具有Python编程的基础知识,至少需要将Python安装好。如果暂时还不满足这一要求的,建议先关注公众号 IT信息教室,学习 Python入门教程。
内容首发于微信公众号IT信息教室,如果您想学习更多AI相关的技能,欢迎搜索关注或微信扫描下方二维码关注~~
前面几期的教程中,我们学习了从网上获取交易数据的方法,学习了将数据可视化的方法,学习了简单的数据清洗和数据合并的方法,另外,我们还学习了分析数据之间的相关性以及将相关性关系以可视化的方式展现出来。
接下来,我们将进一步处理这些数据,并基于这些数据,借助机器学习的一些方法帮助我们更深入的分析和预测现有以及未来的数据。
同样以这里的股票数据为例,我们知道,随着时间的推移,数据之间可能存在一些相关性。例如,一个公司的股票走势,可能会受到其他相关公司的股票走势的影响,那么如果能够让计算机找到并且模拟这一相关性的关系,从某种程度上来说,我们就可以预测特定公司未来的交易信息。
这一目标可以通过‘机器学习’来实现。机器学习的过程实际上是去建立数据的特征与标签的映射关系,并把所有的标签分类。有了这样一种关系之后,给定一个特征,‘机器’ 就会将特征映射为一个‘标签’,这个标签所属的类别就可以作为预测的结果。
对于股票数据来说,特征可以是股票的价格。一般的,为了让预测结果更加准确,需要选取一些有代表性的特征。
我们选取未来几天内每一支股票价格的变化率作为特征,将股票的变化趋势作为标签,我们将一部分标签分为继续买入一类,一部分作为卖出类,其余部分作为继续持有类。
例如我们可以规定,对于股票 A,如果在接下来的 x 天内,股票成交价的增幅可能在 y% 以上,我们就在当前时间点继续买入这家股票。如果未来 x 天成交价的降幅在 y% 以上,我们就在当前时间点卖出这家股票。对于其他预测结果,我们选择继续持有这家股票。
所以,我们的目标是使用机器学习方法,预测未来 x 天的交易信息,并给出指导性的交易方案(买入/卖出/继续持有)。
我们首先生成交易信息的特征数据,按照前面的分析,在当前时间点,我们选取最多 x 天后股价相对于当前时间点股票变化的百分比作为特征。
例如取 x=7,那么对于股票 A,我们就建立 7 列特征数据,分别表示 1 天后,2 天后,…,7 天后的股价相比于当前股价的变化率。我们使用函数 processDataForLables 来实现这一功能:
def processDataForLables(ticker):
函数的参数是股票代码,我们需要为每一支想要分析的股票建立特征数据。
这一期我们主要还是以每支股票的复权收盘价为例,与往常一样,首先读取交易数据:
dataFrame = pd.read_csv('SS50JoinedClose.csv', index_col=0)
然后对数据进行简单的过滤清洗,将空白数据都用 0 填充:
dataFrame.fillna(0, inplace=True)
另外,为了方便后续的一些操作,先提取所有的股票代码,以列表的格式保存在变量 tickers 中备用:
tickers = dataFrame.columns.values
接下来,设置数据的特征:
nDays = 7
for i in range(1, nDays+1):
dataFrame['{}_{}d'.format(ticker, i)] = (dataFrame[ticker].shift(-i) - dataFrame[ticker]) / dataFrame[ticker]
我们使用 shift(-i) 这个方法获取 i 天后的收盘价。这里生成了 7 天内的特征值,对于名称为 ticker 的股票,生成 7 列特征值,每一列的索引名称为 ‘ticker_1d’, ‘ticker_2d’, … , ‘ticker_7d’。
接下来,再对生成的数据进行简单的处理,同样的方法,将空白的位置填充上 0:
dataFrame.fillna(0, inplace=True)
这样对于任意给定的股票,就生成了它的特征信息,最后函数范围生成的特征值,为了后续方便使用,我们同时返回所有的股票代码:
return tickers, dataFrame
最后测试一下,以 ‘600585.SS’ 这支股票为例:
tickers, dataFrame = processDataForLables('600585.SS')
print(dataFrame)
参考输出如下
600036.SS 601229.SS ... 600585.SS_6d 600585.SS_7d
Date ...
2010-01-04 11.171289 0.00 ... -0.050209 -0.090043
2010-01-05 11.183971 0.00 ... -0.078956 -0.072449
2010-01-06 10.950527 0.00 ... -0.074588 -0.078360
2010-01-07 10.666690 0.00 ... -0.048042 -0.045659
2010-01-08 10.666690 0.00 ... -0.047514 -0.011015
... ... ... ... ...
2020-11-23 45.400002 7.98 ... 0.000000 0.000000
2020-11-24 44.869999 7.94 ... 0.000000 0.000000
2020-11-25 44.430000 7.93 ... 0.000000 0.000000
2020-11-26 45.090000 7.96 ... 0.000000 0.000000
2020-11-27 45.849998 8.09 ... 0.000000 0.000000
[2649 rows x 57 columns]
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@author: IT信息教室(微信公众号)
订阅/关注,在看、分享三连吧~
"""
def processDataForLables(ticker):
dataFrame = pd.read_csv('SS50JoinedClose.csv', index_col=0)
dataFrame.fillna(0, inplace=True)
tickers = dataFrame.columns.values
nDays = 7
for i in range(1, nDays+1):
# The increasing rate of adj close with i day(s).
dataFrame['{}_{}d'.format(ticker, i)] = (dataFrame[ticker].shift(-i) - dataFrame[ticker]) / dataFrame[ticker]
dataFrame.fillna(0, inplace=True)
return tickers, dataFrame
tickers, dataFrame = processDataForLables('600585.SS')
print(dataFrame)