RAV四NN建立股票预测模型,机器学习在量化投资中的应用

  硕士毕业之前曾经对基于LSTM循环神经网络的股价预测方法进行过小小的研究,趁着最近工作不忙,把其中的一部分内容写下来做以记录。

机器学习算法分类

机器学习主要分为三种类型,监督学习(Supervised
Learning)、无监督学习(Unsupervised Learning)和强化学习(Reinforcement
Learning)。我们对主流分类方法来介绍机器学习在量化投资中的应用,实际上,各种方法的应用模式可以互相交叉。

监督学习的主要目的是使用有类标的训练数据构建模型,我们可以使用经训练得到的模型对未来数据进行预测。术语监督是指训练数据集中的每个样本均有一个已知的输出项。如利用分类对类标进行预测、使用回归预测连续输出值。

在无监督学习中,将处理无类标数据或者总体分布趋势不明朗的数据,通过无监督学习,我们可以在没有已知输出变量和反馈函数指导的情况下提取有效信息来探索数据的整体结构。如通过聚类发现数据的子群,数据压缩中的降维。

强化学习的目标是构建一个系统,在与环境交互的过程中提高系统的性能。环境的当前状态信息中通常包含一个反馈信号,我们可以将强化学习视为与监督学习相关的一个领域,然而,在强化学习中,这个反馈值不是一个确定的类标或者连续类型的值,而是一个通过反馈函数产生的对当前系统行为的评价。通过与环境的交互,系统可以通过强化学习来得到一系列行为,通过探索性的试错或者借助精心设计的激励系统使得正向反馈最大化。一个常用的强化学习例子就是象棋对弈的游戏,在此,系统根据棋盘上的当前局态(环境)
决定落子的位置,而游戏结束时胜负的判定可以作为激励信号。AlphaGo
就是强化学习的成功应用。

前言

如上一篇所述,这篇文章讲一讲建模的后续:如何提高benchmark模型性能。

先说一下结论:在获得更好的预测模型这件事上,我失败了。

对,没错,我没有成功提高模型预测率。无论是处理非平衡数据,特征归一化,独热编码,还是运用不同算法,我都没办法提高模型预测率,它们的结果要么和benchmark模型差不多,要么更差。

这其中的原因可能有:

  • 特征工程做得不好。老实说,由于UCI的这个数据集相当完整(足够多的变量,没有缺失值,没有异常值),在特征工程方面我没有太多的想法。
  • 算法选择不当或调参不当。在这几天的建模实验里,除了对sklearn本身不熟悉之外,我发现我的理论基础有所欠缺,所以在用某种算法的时候,面对一箩筐的参数,常常心有余而力不足。接下来的几周里,我打算好好回顾算法,巩固理论基础。

但除去这些,还是有一些有趣的发现。下面我会具体描述我在建模过程中做过的尝试,以及从中得到的发现。

 

机器学习在量化投资中的应用

监督学习:对未来事件进行预测

1、 回归——预测连续型目标变量

(1) OLS 回归

OLS
回归的目标是:求误差的最小平方和。对于线性回归模型,最小二乘有解析解,即:

图片 1

非线性最小二乘没有解析解,通常用迭代法求解。

最小化代价函数的迭代法有:梯度下降法,可以用于线性和非线性模型;高斯-牛顿法,用于非线性模型;
Levenberg-Marquardt
法,结合了梯度下降和高斯-牛顿法,用于求解非线性模型。

(2)正则化方法——岭回归、LASSO回归、弹性网络

正则化是通过在模型中加入额外信息来解决过拟合的一种方法。加入的信息称为惩罚项,惩罚项增加了模型的复杂度,但降低了模型参数的影响。

常用的正则化线性回归方法有:基于 L2 罚项的岭回归、基于 L1 罚项的 LASSO
回归, 以及结合了 L1 与 L2 的弹性网络。

岭回归:在最小二乘的代价函数中加入权重的平方和。其中增加超参λ的值可以增加正则化的强度,同时降低了权重对模型的影响。

图片 2

LASSO 回归:在最小二乘的代价函数中加入权重绝对值的和。

图片 3

弹性网络:包含 L1 罚项和 L2 罚项。

图片 4

(3)评价回归模型性能的方法

残差图:对于一个好的回归模型,期望误差随机分布,残差也随机分布于中心线附近。

均方误差(MSE):最小化误差平方和(SSE)的均值,可用于不同回归模型的比较,
参数调优和交叉验证。

图片 5

决定系数( R2 ):MSE 的标准化版本,预测值的方差。

图片 6

(4)实例:OLS、LASSO、岭回归拟合月收益率

以沪深 300 成分股为基础,选择 PE、PB、ROE、LFLO、20
日资金流量、应付账款周转率、净利润增长率、当前价格处于过去 1
年股价中的位置这 8 个因子构造模型,使用20110801-20130531
的月数据用来训练,20130601-20171001 进行回测,按月调仓;

首先对数据进行去极值、中性化、标准化、归一化处理,再分别采用三种不同的模型在训练集上获取回归系数,根据调仓日前一天的因子与回归系数的乘积作为分数,取排名前
20 的股票,按分数在合计分数中的比例计算买入权重;

分别应用 OLS、LASSO回归、岭回归的回测结果净值如下:

图片 7

OLS回归

图片 8

LASSO回归

图片 9

岭回归

2、 分类——预测分组或标签

(1) logistic回归

Logit回归(logistic regression)是一个分类模型。它通过一个Logistic
函数将输入映射到[0,1]区间,logistic 函数又称sigmoid函数,形式如下:

图片 10

其中,输入 Z:

图片 11

Logit回归模型可以看做由两部分组成,一部分和线性回归一样,另一部分是sigmoid
函数。直观形式如下图:

图片 12

Logistic回归

逻辑斯蒂模型的求解:归结为以似然函数为目标函数的优化问题,用迭代法求解。

逻辑斯蒂回归并不是硬性地将分类结果定为 0 或 1,而是给出了 0 和 1
之间的概率。这相当于对分类结果给出了一个打分。例如我们想选出沪深 300
成分股中上涨概率最大的前 30
只股票,我们可以用逻辑斯蒂回归的结果对每只股票算出一个打分,分数越接近于1
上涨概率越大,只要选出打分排名前 30
的就可以了。另外也可以规定一个阈值,大于阈值的归为一类,小于阈值的归为另一类。

(2) SVM

SVM(support vector
machine)俗称支持向量机,是一种监督学习算法,可用于分类和回归。它在解决小样本、非线性及高维模式识别中表现出许多特有的优势。

支持向量机分类的原理如下:

假设有两个类别:实心圆和空心圆,我们的数据有两个特征:x 和
y,需要得到一个分类器,给定一对(x,
y),输出实心圆和空心圆。我们将已标记的训练数据展示在下图:

图片 13

SVM分类

假设我们要把实心圈和空心圈分成两类。支持向量机会接受这些数据点,并输出一个超平面(在二维图中是一条直线)将两类分割开来。两类中,分别有距离分界线最近的点,
被称为支持向量(图中加粗的圆点)。而我们要寻找的最优的分界线要满足:支持向量到最优分界线的距离最大。

用数学表达式表述:

定义直线

图片 14

任意点 x 到该直线的距离为

图片 15

N 个训练点的信息记为

图片 16

分类器满足

图片 17

以上分类原理可拓展至高维平面。

我们已经了解到了 SVM 处理线性可分的情况,对于非线性的情况,SVM
的处理方法是选择一个核函数,通过将数据映射到高维空间,最终在高维特征空间中构造出最优分离超平面,来解决在原始空间中线性不可分的问题。

(3)决策树、随机森林

决策树

决策树最吸引人的地方在于其模型的可解释性。正如其名称“决策树”所意味的那样,我们可以从树根开始,根据节点的不同变量值划分建立树的分枝,自顶向下重复建下层和分枝,直到完成建立整棵决策树。

在每一个节点,选择可获得最大信息增益(information
gain,IG)的特征来对数据进行划分。通过迭代重复此划分过程,直到叶子节点。在实际应用中,这可能会导致生成一棵深度很大、拥有众多节点的树,即发生过拟合,为此,一般通过“剪枝”限定树的最大深度。

最大信息增益即每次划分时优化的目标函数,为了实现每次划分对信息增益的最大化。

信息增益:

图片 18

其中,f 为将要进行划分的特征, Dp 和 Dj 分别是父节点和第 j 个子节点,I
为信息含量, Np 和 Nj
分别为父节点和子节点中的样本数量。所以信息增益即父节点信息与子节点信息之差。

信息 I 一般有三个度量标准:基尼系数( IG )、熵( IH )、误分类率( IE
)。

最常用的是熵,其定义为:

图片 19

其中, p( i | t) 为节点 t 中,属于类别 c 的样本占节点 t
中总样本数的比例。

随机森林

随机森林可以看作多棵决策树的集成,通过多数投票的方式对每棵决策树的结果汇总。随机森林具有更好的鲁棒性,因此一般不需要剪枝。

(4)K-近邻算法

K-近邻算法(K-nearest
neighbor,KNN)是惰性学习算法的典型例子,惰性学习在学习阶段的计算成本为
0。

KNN算法非常简单,首先,选择近邻的数量 k
和距离度量方法;然后找到待分类样本的 k
个最近邻居;最后,根据最近邻的类标进行多数投票。

图片 20

KNN算法

(5)神经网络、深度学习

神经网络

人工神经网络是模仿大脑神经元之间信息传递的模型,可以以任意精度逼近任意函数,
能够处理各种复杂的非线性关系,多用于处理分类问题。

下图描述了一个简单的神经元:

图片 21

单个神经元

这个神经元是一个以 x1, x2, x3及截距+1为输入值的运算单元,其输出为:

图片 22

函数 f 被称为激活函数。常用的激活函数有 sigmoid 函数

图片 23

和双曲正切函数

图片 24

神经网络是将多个单一神经元联结在一起,一个神经元的输出可以成为另一个神经元的输入。

图片 25

神经网络模型

神经网络由最左边输入层、最右的输出层(本例中,输出层只有一个节点)和中间隐藏层构成。上图的神经网络例子中有
3 个输入单元(偏置单元不计在内),3 个隐藏单元及一个输出单元。

深度学习

当前多数分类、回归等学习方法为浅层结构算法,其局限性在于有限样本和计算单元情况下对复杂函数的表示能力有限,针对复杂分类问题其泛化能力受到一定制约。深度学习可通过学习一种深层非线性网络结构,实现复杂函数逼近,具有强大的从少数样本集中学习数据集本质特征的能力。

深度学习的实质是通过构建具有很多隐层的机器学习模型和海量的训练数据,来学习更有用的特征,从而最终提升分类或预测的准确性。

深度神经网络的训练机制与传统神经网络不同。传统神经网络采用反向传播的训练机制,即通过残差的反向传播调整权重。深度神经网络层数较多,残差传播到最前面的层已经变得太小,会出现梯度扩散的问题。

深度神经网络采用的训练机制为逐层初始化。

简单的说,分为两步,一是每次训练一层网络,二是调优。深度学习训练过程具体如下:

1)使用自下上升非监督学习(从底层逐层向顶层训练):

采用无标定数据(有标定数据也可)分层训练各层参数,这一步可以看作是一个特征学习过程,是和传统神经网络区别最大的部分。逐层学习每一层的参数,每一步可以看作是得到一个使得输出和输入差别最小的三层神经网络的隐层。使得得到的模型能够学习到数据本身的结构,得到比输入更具有表示能力的特征;

2)自顶向下的监督学习(就是通过带标签的数据去训练,误差自顶向下传输,对网络进行微调):

基于第一步得到的各层参数进一步微调整个多层模型的参数,这一步是一个有监督训练过程;第一步类似神经网络的随机初始化初值过程,由于深度学习的第一步不是随机初始化,而是通过学习输入数据的结构得到的,因而这个初值更接近全局最优,从而能够取得更好的效果;所以深度学习效果好很大程度上归功于第一步的特征学习过程。

(6)实例:决策树对沪深 300 走势分类

模型构建:

模型的输入因子,我们选取了三个大类,分别是市场前期走势、宏观经济指标和利率因素。

市场走势中选取沪深 300
指数上一个月收益率、上一个月区间波动率作为因子,以期反映市场在波动、动量等维度的信息;在宏观经济指标中,我们选取了
GDP(国民经济生产总值,当季同比)、CPI(消费者物价指数)、PMI(采购经理人指数)、Capital
Investment
(固定资产投资完成额,当月同比)等与 A
股市场关系密切的变量作为因子;类似地,在利率因素中则选取了 YTM1Y(1
年期国债到期收益率,当月同比)、M2(广义货币,当月同比)。宏观经济指标和利率因素数据中由于
CPI、M2 等数据一般都在月中公布,因此我们在预测中使用的是滞后一期的数据。

时间区间为 2005 年 1 月至 2017 年 7 月,训练时间为 36
个月,采用滚动训练预测的方式。用 t-36 到 t-1
月的因子数据为训练样本,进行样本内的参数测算,再用其来预测第 t 个月沪深
300 指数的涨跌。

所有的数据我们都进行了异常值、缺失值等各种预处理。在每个月的月末判断下个月沪深
300
指数的涨跌,并将该结果与下个月的真实涨跌情况进行比较,计算决策树方法预测的准确率(预测正确个数/预测期总月份数)。

采用改进后的 CART 方法,加入了自动剪枝过程,从而减少过拟合。

下图为一个样本生成树的示例:

图片 26

决策树分类示例

下图显示了决策树(CART)模型的涨跌预测准确率的变化过程。在总共 114
个预测期内我们预测大盘涨跌正确的月份达到 68 个,也就是说准确率达到了
60%的水平。从准确率随时间变化趋势来看,除去刚开始时的波动,后期基本稳定在
60%上下,整体准确率还算是较为理想。

图片 27

决策树分类准确率变化

接下来我们考虑以上述决策树预测为基础的择时策略(对应下图中 CART
Strategy):如果模型看涨则在下一个交易日全仓买入,看跌则在下一个交易日清仓(假定初始购入资金为
10 万,单边买卖的成本定为 0.5%)。与之对应的为基准交易策略(对应下图中
HS300 Strategy),即在开始时全仓购入沪深 300
指数并持续持有。由此我们得到了下图中两种
策略的资产净值比较:尽管 2008-2017
年期间大盘整体表现不佳,但决策树策略仍然保持了为正的累计收益率,并且其收益率比持续持有沪深
300 指数要高出 21.3%。

从下图中可以看出,这部分高出的收益率主要来自于决策树策略能够有效地规避大部分下跌(大盘指数下跌时
CART Strategy 曲线大多走势平缓),并且把握住了主要的上涨
行情。但我们也发现决策树策略的上涨行情的把握略差于对下跌行情的规避,尤其是2015-16
年间的一波中级牛市,基本没有较大幅度的上涨(还好规避掉了后来大盘的下跌)。究其原因,我们认为像经济指标的滞后、因子覆盖面不足(例如忽略了市场情绪变化)等
都是可能干扰决策树模型的噪声。

图片 28

决策树择时与基准净值变化

无监督学习:发现数据的潜在规律

1、聚类——无类标数据潜在模式的挖掘

(1)K-means

K-means
计算高效,易于实现,是一种经典的聚类技术。它是根据样本之间的相似性对样本进行分组,划分为k个类簇,组内的对象之间具有更高的相似度。相似性的度量通常采用欧氏距离的倒数。

初始状态下,随机选取k个点作为初始类簇中心。随后将每个样本依据相似度划分到离它最近的中心点,并重新计算每个簇的中心。重复这一步骤,直到中心点不变或者达到预定的迭代次数时终止。

实际运用中,初始k个中心点的选取以及聚类簇数k对结果的划分有较大影响。因此,
除了随机选取初始中心,我们还有两种其他的方式选取初始中心。

初始中心的选取

1、 选择批次距离尽可能远的 k
个点:首先随机选择一个点作为第一个初始类簇的中心点,然后选择距离它最远的那个点作为第二个初始类簇的中心点,然后再选择距离前两个点的最近距离最大的点作为第三个初始类簇的中心点……直到选出
k 个初始类簇的中心点。

2、 选用层次聚类或 canopy
算法进行初始聚类,然后利用这些类簇的中心点作为k-means
算法初始类簇中心点。

K 值的确定

通过选定一个类簇指标,比如平均半径或直径,当假设的簇数 k
大于等于真实的类簇数目时,该指标上升很慢,而少于真实数目时,该指标会急剧上升。类簇指标变化的拐点最接近真实类簇数目。

其中,类簇的半径指类簇内所有点到类簇中心距离的最大值。类簇的直径指类簇内任意两点之间的最大距离。

图片 29

类簇指标变化的拐点为最佳 K 取值

(2)层次聚类

层次聚类无需事先指定簇数量。层次聚类有两种:凝聚(agglomerative)层次聚类和分裂(divisive)层次聚类。

凝聚层次聚类是一个自下而上的聚集过程,初始时把每个样本看作一个单独的簇,重复地将最近的一对簇合并,直到所有样本都在同一个簇中为止。由此生成整个树形图。在这个过程中,度量两个簇之间距离的方式有三种:

单链(single-link):不同两个聚类簇中离得最近的两个点之间的距离(即
MIN);

全链(complete-link):不同两个聚类簇中离得最远的两个点之间的距离(即
MAX);

平均链(average-link):不同两个聚类簇中所有点对距离的平均值(即
AVERAGE)。

而分裂层次聚类是自上而下的,首先把所有样本看作在同一个簇中,然后迭代地将簇划分为更小的簇,直到每个簇都只包含一个样本。

层次聚类的缺点在于计算开销比较大。

(3)实例:趋势动量模式聚类选股模型

策略思路:使用聚类的方法,找到短期内表现较好股票的动量和趋势模式特征,选择最接近该特征的股票构建投资组合,使得组合能够在较短周期内取得较好收益。

策略的大致流程如下所示:

1、在 t 时刻,计算所有股票在
t-20时刻的动量和趋势指标值(计算方法见下),根据股票的指标值和市值(均已去极值标准化处理)对所有股票进行
K-means 聚类,得到M个股票组(类别);

2、每个股票组构成一个投资组合,假设对组合内每只股票等权重分配资金,计算每个投资组合从
t-20 持有至 t 天的组合收益值;

3、对 M
个组合的收益值进行排序,找到排序最高的股票组合,并得到这个类别的指标中心向量,记为
center;

4、在 t 时刻下计算所有股票的指标向量,计算每个向量与最优中心 center
的欧氏距离,按照距离由小到大排序,得到前 20
支股票,作为当前选出的股票组合进行投资, 持有 20 天后卖出;

5、策略逐日滚动。

策略所采用的动量和趋势指标计算方法如下:

ROC(rate of change) = (Pricetoday – Pricen days ago) / Pricen days ago
* 100 TrendIndicator = (Price – EMA) / EMA * 100

其中,EMA 为股价的指数移动均值。分别选取 125 天 ROC、20 天 ROC 和 200

TrendIndicator、50 天 TrendIndicator 为长、短周期动量和趋势指标。

对 2007 年 1 月 1 日至 2017 年 7 月 14 日全 A
股市场所有股票的日线数据进行分析,基准分别选取上证综合指数和沪深 300
指数。

交易手续费设置为双边千分之三,使用收盘价计算策略指标,使用发出交易信号第二天的开盘价进行交易。初始资金等分为
20 份,用于一个 20 天周期内不同交易日的策略交易,各份资金之间互不影响。

在构建投资组合时,剔除停牌以及上市未满一年的股票。策略表现如下:

图片 30

聚类数为 10 的长短期 ROC 指标聚类图

图片 31

聚类数为 10 的长短期 trend 指标聚类图

图片 32

聚类数为 10 的净值表现

2、降维——数据压缩

(1)主成分分析

对不适合正则化的模型,可以用主成分分析或者线性判别分析降维。

主成分分析是一种常用的降维方法,能够在尽可能多地保留相关信息的情况下,把多指标转化为少数几个综合指标。

其基本原理是把数据沿着方差最大的方向映射到维度更低的子空间上,新特征的坐标相互正交。如果原始数据是
d 维,新的子空间是 k 维( k ≤ d ),那么我们需要构建一个d×k维的转换矩阵
W。

构造转换矩阵的基本步骤是:首先对数据标准化,并构造样本的协方差矩阵,求协方差矩阵的特征值和特征向量,选择与前
k 个最大特征值对应的特征向量构建映射矩阵。

(2)线性判别分析

线性判别分析(linear discriminant
analysis,LDA)是一种监督的数据压缩方法。使用 PCA 降维时, PCA
可以把两个特征合并为一个,但 PCA
没有类别标签,如果这两个特征对于类别标签的分类没有任何影响,那么我们完全可以把这两个特征去除。LDA
就是要从高维特征中抽取出与类别标签关系最密切的低维特征。

假设我们有两个类别标签,当原始数据是二维,想将二维降到一维,我们可以把数据投影到最佳向量
w 上,使得类别间的距离最大,每个类别内部点的离散程度最小。

图片 33

线性判别分析

找最佳向量 w 的过程如下:

1、 对 d 维数据进行标准化处理,并计算 d 维的均值向量:

图片 34

2、 构造类间散布矩阵 SB 及类内散布矩阵 SW:

图片 35

其中,m 为全局均值,

图片 36

3、 计算矩阵

图片 37

的特征值及特征向量;

4、
提取前k个特征值所对应的特征向量,构造d×k维的转换矩阵W,其中特征向量以列的方式排列;

5、 使用转换矩阵把样本映射到新的子空间。

(3)实例:主成分因子降维

我们选取2017 年第一季度沪深300
成分股的每股收益和资产收益率,并进行标准化,
得到下图的二维数据点。我们希望找到一条直线,使得这一方向上的数据值对方差的影响最大,即,将数据点投影到这条直线后,得到的方差最大。

图片 38

每股收益和净资产收益率主成分分析

上图的直线是第一主成分所在的维度。新特征 Z 为第一主成分:

Z = 0.707×1-0.707×2

通过主成分分析的方法,我们将相关性较高的两个因子,每股收益和资产收益率降为一个一维特征。

强化学习:交互式最大化收益

1、强化学习

强化学习(Reinforcement
Learning)是让计算机实现在特定的情况下,通过不断地尝试, 从错误中学习,
最后找到规律,
找到可以获得最大回报的行为。强化学习有四个基本组件,包括输入:环境(States),动作(Actions),回报(Rewards)以及输出:方案(Policy)。和监督学习不同,强化学习没有确定的标签,需要机器自己摸索,每一个动作对应一个奖赏,最后得到一个奖赏最大的方式进行数据处理。AlphaGo
就是一个强化学习的实例。强化学习的主要算法有:Sarsa,Q Learning, Policy
Gradients, Actor-Critic, Deep-Q-Network 等。

图片 39

强化学习

强化学习的目标是发现最优策略π(x),使得达到最优价值Q
。主要有两种途径可以学习最优值函数:一种是基于模型的学习,
在学习的过程中对模型进行估计, 如实时动态规划(Real-Time Dynamic
Programming, RTDP);另一种是无模型学习,
在学习的过程中直接估计最优行动值。

Q学习算法是 Watkins 在 1987
年提出的一种无模型强化学习算法:它用状态s下采取行动的下一个状态s’,对假定的行动s’所对应的最大Q’值更新当前的Q值。

2、实例:Q 学习优化投资组合权重

由前文介绍可知,对于系统环境变动频繁的动态决策问题,
强化学习Q算法具有不断试错、优化调整的特点。而量化投资同样面临着具有高风险和高不确定性的环境,而且往往需要在不同阶段动态调整不同股票的投资比例,这些问题通过强化学习Q算法可以得到较好的解决。

假设此组合投资系统在第t-1阶段投资时对股票 i 的未来绩效评价值为Y(i,t –
1),期望值为Yˆ(i,t –
1)。在第t-1期投资结束时,对投资结果进行评价,并计算下一期绩效的期望值:

图片 40

第t期结束后,计算股票i 运作绩效变化率:

图片 41

接下来对该股票的投资权重K(i,t) 进行调整:

图片 42

其中a是一个决定学习速度的正恒量,一般取a = 0.1。

也就是说,如果Y(i,t) >
Yˆ(i,t),即股票i在第t期的表现超出预期,则对其进行“奖励”,增加股票i的投资比例;否则其将受到惩罚,
即调低该股票的投资比例,直到退出为止。最后对所有股票的权重再统一乘以一个系数,以保证所有权重的加总为
1。

先来回顾一下banchmark模型

图片 43

001 – ROC curve of the benchmark model

这个banchmark模型用的是XGBoost,AUC值为0.8044,模型整体性能不错,但从ROC曲线可以看到,假阳性率(FPR)低的时候,对应的真阳性率(TPR)不高,比如0.2的FPR对应的TPR不到0.7,说明模型没有能很好地捕捉到
class = 1(y = yes)的pattern。

一个可能的原因是数据的非平衡性,即目标变量y下的两个类目(yes和no)占比不均:y
= yes
的客户只占了总客户的11.27%,不到三分之一。大多数现有算法不能很好地处理非平衡数据。

基于此,我首先尝试通过sampling来解决非平衡问题。

  此次股票价格预测模型仅根据股票的历史数据来建立,不考虑消息面对个股的影响。曾有日本学者使用深度学习的方法来对当天的新闻内容进行分析,以判断其对股价正面性/负面性影响,并将其与股票的历史数据相结合,各自赋予一定的权重来对近日的股价进行预测\[1\]。该预测方法取得了一定的效果。

AI+量化的应用和展望

AI 在国内的应用仍有一定的局限性,目前 AI
在国内投研投顾领域主要用于辅助决策与用户画像上。将来有望落地的将会是“AI+”的量化投资模式,即在传统量化思想的基础上,恰当地运用一些
AI 算法,帮助贡献有益的投资决策。长期来看,全面 AI
还很遥远。这一方面是由于,AI 学习的效果跟数据的质量有很大关系,我国 A
股市场发展的时间还不长,数据量不够充足,噪声也比较多,使 AI
学习效果的稳定性不能得到充分的保证。另一方面,脱离人类经验的完全强化学习目前仅在有特定约束条件的环境下成功运用,
离普适还有相当距离,深度学习、强化学习等技术仍需要 GPU、TPU 发展的支持。

人工智能,在金融领域已经开始逐步从探索走向应用,从金融大数据,到智能投顾、智能投研,在不断取得新的应用进展。依托于计算机和数据信息的发展,“AI+”的模式将给我们的投资研究带来更多的助益。未来将在“AI+”量化投资中探索更多的想法和应用。

数据非平衡问题 Imbalanced Data

处理非平衡问题一般有以下几种方式:

  1. 什么也不做
  2. 通过某些sampling方法使数据变得平衡
  3. 在算法的构造、选取和调试上寻求解决方法

我在方式2上进行了尝试,具体方法有:

  • Under-sampling:random under-sapling
  • Over-sampling:SMOTE
  • Combined method:SMOTEENN

实现sampling的python封装是imbalanced-learn,具体可以看它的GitHub。

通过上述这三种sampling方法,我构造了三个不同的训练集,并使用XGBoost分别对它们进行训练,训练结果如下。

  而这里我没有引入消息面的影响,主要出于以下几点考虑:

1. Random Under-sampling

Under-sampling的思路是,通过减少多数类(数量占比大的class)的数量,使得训练集中的两个类别在数量上大体相等。

因为我的数据集有4w+数据,即使是用under-sampling,所剩下的数据在数量上也是比较可观的。如果数据量原本就很少,就不要在用under-sampling啦。

图片 44

002 – ROC curve with under-sampling data

蓝色是使用了under-sampling数据的训练结果,橙色是benchmark模型。很明显,under-sampling无功无过,几乎对结果没什么影响(AUC稍微降低至0.8025)。

如果说在数据量足够的情况下,做under-sampling之后,其返回的训练结果没什么差异,那么对于大数据来说,是不是能用under-sampling数据来训练模型,从而提高计算效率呢?

  1.消息的及时性难以保证:很多时候,在一只股票的利好/利空消息出来之前,其股价已经有了较大幅度的增长/下跌。信息的不对称性导致普通群众缺乏第一手消息源。

2. SMOTE

SMOTE全称为Synthetic Minority Oversampling
Technique,其思路是通过某种特定方式合成新的少数类样本,使得训练集中的两个类别在数量上大体相等。

合成的策略是,对每个少数类样本a,从它的最近邻中随机选一个样本b,然后在a、b之间的连线上随机选一点作为新合成的少数类样本。

我的数据量并没有上10w,所以就算做over-sampling,模型的训练速度也没有很慢。对于大数据来说,做over-sampling要慎重。

图片 45

003 – ROC curve with SMOTE data

橙色是使用了SMOTE数据的训练结果,蓝色是benchmark模型。很明显模型预测性变差了=。=

原因可能是通过SMOTE生成的数据放大了原始数据中不必要的noise,导致模型过拟合(over-fitting)。用XGBoost的时候我用了watchlist,训练的时候训练集和验证集的AUC差别很大,前者有0.95左右,而后者只有0.78左右。(但无论我怎么调参,始终都是过拟合……)

顺带一提,我一开始是对训练集和验证集都做了SMOTE,所以训练的时候二者的AUC都很高也很接近,但后来发现这样做并没有什么意义(也很蠢……),因为测试集的AUC其实很差。后来改成只对训练集做SMOTE,结果则变成验证集和测试集的AUC很接近(也都很差)。但在同等训练条件下(同算法,同参数),后者的结果比前者要稍微好一点。

  2.消息的准确性难以保证:互联网上信息传播速度极快,媒体之间经常会出现相互抄袭新闻的情况,而这种抄来的新闻(非原创新闻)往往没有经过严格的审核,存在着内容虚假,夸大宣传的可能性。一旦分析模型错用了某条谣言或真实性不高的新闻,很有可能得出错误的预测结果。

3. SMOTEENN

SMOTEENN是SMOTE和ENN(Edited Nearest
Neighbours)的结合,前者是over-sampling过程,后者是under-sampling过程。

SMOTEENN的思路是通过SMOTE合成新的少数类样本,然后通过ENN清洗SMOTE过程中产生的噪点(noisy
samples)。

图片 46

004 – ROC curve with SMOTEENN data

橙色是使用了SMOTEENN数据的训练结果,蓝色是benchmark模型。同样的,前者的表现差于后者。

但值得注意的是,SMOTEENN数据的训练结果比SMOTE数据的要好,这侧面说明了SMOTE产生了噪点,使得模型过拟合。

  3.语言的歧义性:一条新闻,其正面性/负面性往往存在着多种解读。例如“习主席宣布中国将裁军30万”——新华每日电讯2015.09.04。这条新闻一般意义上可以解读为:中央政府深入推进改革,精兵简政,大力发展国防军工事业。这是一种正面性的解读。而在使用机器学习模型时,如传统的奇异值分解算法(SVD),很有可能会判定其与“去年五大行裁员近3万”这种新闻具有较高的相似度,因而将其划分为负面新闻。

小结

对于此次分析中用到的数据集,三种sampling方法都没能提高模型性能,而在模型表现上,Random
Under-sampling优于SMOTEENN,SMOTEENN优于SMOTE。

  4.技术实现较为繁杂:这其实是一个非常重要的原因啦~,获取正确的信息并进行NLP操作,往往需要经过以下流程:人工浏览网页确定稳定可靠的信息源→设计爬虫实现有效信息的获取→设计新闻裁剪(填充)方案以应对不同长度的新闻→人工标注新闻的正/负性(也可以用当日股价涨跌来标注)→设计网络模型→训练及验证模型。其中的每一步都非常麻烦耗时,而且对于个股来说,并不是每天都会有新闻出现。

特征归一化与独热编码

之前有说到,数据不同级可能会对算法的学习效果有影响,所以训练模型之前,特征归一化(scaling)是一个值得尝试的步骤。

此外,不少模型都不能很好地处理类别变量(categorical
variable)。如果简单地把类别变量用整数表示(比如在性别变量中,用1表示男性,2表示女性),则可能使得算法将类别变量视作interval变量,从而产生bias。所以在建模之前,需要处理类别变量。一个常用的方法是独热编码(one-hot
encoding)。

(顺带一提,我用sklearn下的算法训练模型的时候,category型数据可以直接输入,但XGBoost不可以,不知道是算法本身可以处理category,还是sklearn在跑模型前会自动把category转换成int。)

在这一部分,我构造了三个不同的数据集来训练XGBoost模型:

  • 数值型变量归一化
  • 类别变量独热编码
  • 数值型变量归一化 + 类别变量独热编码

目的是为了看看特征归一化和独热编码对XGBoost有什么影响。

对了,由于上一节中,sampling之后的数据并没能提高模型性能,所以这部分我依旧用原数据集来做。

结果如下:

三种情形下的ROC曲线我就不放了,因为都和benchmark模型的差不多(曲线基本重合),说明XGBoost还是比较稳健的,嗯……

数据 AUC
原数据集 0.8044
数值型变量归一化 0.8024
类别变量独热编码 0.8047
数值型变量归一化 + 类别变量独热编码 0.8048

上表是原始数据集下和上述三种情形下对应的XGBoost模型在测试集上的AUC值。

可以看到,四种情形下的XGBoost模型的AUC值很接近,硬要说的话,归一化和独热编码都做之后的模型表现最好,且综合比较,独热编码比归一化的影响要大。

 

其他算法

除了XGBoost,分类问题中还有很多算法可以选择。我简单跑了一下LightGBM,
GBDT,Random Forest和Logistic Regression。

和XGBoost一样,我并没有很仔细地调参,一来是我还不熟悉sklearn,二来是我的理论基础还不够以至于心有余而力不足,三来是想看看相似情况下(都没有好好调参的情况下=。=)哪一种算法表现更好。

另外,因为懒,这部分我用的原始数据集(即没做归一化也没做独热编码)。

结果

这部分的ROC曲线我也不放了,因为还是都和benchmark模型的差不多,曲线基本重合。

AUC值如下。

算法 AUC
XGBoost 0.8044
LightGBM 0.8033
GBDT 0.8071
Random Forest 0.8029
Logistic Regression 0.7842

可以看到LR的表现最差,GBDT表现最好,其余的差不多。

值得一提的是,在训练效率上,LightGBM最快,XGBoost其次,GBDT最慢。

LightGBM是微软去年发布的一个GBM改进算法,号称比XGBoost更高效更轻便。亲自试过之后的感觉是:名不虚传。我估计在可预见的不久的将来,LightGBM会取代XGBoost的地位,毕竟在效果差不多的前提下,前者比后者要快,占的内存也更少。

但有一点不得不提,LightGBM的参数非常多(大概是XGBoost的两倍吧),学习门槛还是比较高的。(我打算回头再好好钻研一下这些参数。)

最后想再回过头来说一下Logistic
Regression。作为广义线性模型的一员,LR还是比较神奇的,虽然很多时候LR都不是最优模型,但在数据质量不高的情况下,LR的稳健性就凸显出来了。

跑完上述模型之后,突然就想看看归一化和独热编码对LR的影响:

图片 47

005 – ROC curve of Logistic Regression

可以看到,无论是单独做归一化,单独做独热编码,还是二者都做,模型的ROC曲线都差不多且性能都比benchmark模型要差一些。但值得注意的是,单就LR来说,做不做归一化、独热编码,影响还是比较大的。

另外,这次我没做WoE编码,以后有时间想把这一块补上,很好奇结合了WoE之后的LR在性能上会不会有明显的提高:)

  上面说了这么多,还没有开始对我这个预测模型进行介绍,下面开始进入正题。在决定排除消息面的考量之后,我开始思考股价涨跌的本质,我认为股价就是资金博弈结果的体现。这次建立的预测模型,朴素的想法是通过深度学习模型来洞悉庄家的操作规律,对拉升、砸盘的情况进行预测。为了达到以下目的,我决定选取以下七个特征来构建网络模型,即:

涨跌幅  最高涨幅  最低跌幅  大单净流入 
中单净流入  小单净流入  换手率

使用这七个特征来对股票的涨跌情况以及资金的流动情况建立适当的模型。此外,其他的指标类似MACD、均线等也是通过一些基础数据的运算得出,在构建模型时并没有将其纳入考量范围。

 

一.源数据及其预处理

  通过某股票交易软件,我获得的源数据约有20来个特征,包括:涨幅、现价、涨跌、买入、卖价、成交量等等。为了得到上面所述的七种特征,挑选出涨跌幅、大单净流入、中单净流入、小单净流入、换手率这5个特征,并计算最高涨幅、最高跌幅两个特征。通过下列公式计算获得。

图片 48

经过处理的股票特征数据存储在 股票名.csv文件中,类似下图:

 图片 49

图中的特征顺序为:日期,大单净流入,中单净流入,小单净流入,涨跌幅,最高涨幅,最高跌幅,换手率,股价。股价在这里的用处是拼接训练样本输出时,计算多日的总涨跌幅。

注:在对源数据进行处理的时候,经常会遇到空值问题:即,有些特征值为0的时候,系统给出的源数据为”-”或”“。需要进行特殊处理。(经常遇见新股第一天的涨跌幅为空,或某交易日大单净流入为空。)

1     if fin_temp.ix[day,12]=='-' or  fin_temp.ix[day,12]=='':  # 新股的涨跌幅一栏会出现'','-',需要特殊处理
2         raise_value = 0.0
3     else:
4         raise_value = float(fin_temp.ix[day,12])

 

 二.训练样本拼接

        
首先设置一个滑动窗口,本次实验中将滑动窗口设置为50个交易日。每一个训练样本由50个连续的交易日组成,每个交易日的数据包含上述的七个特征,即一个50*7的矩阵,而一个样本的输出则是三个交易日之后的收盘价对比今日(即样本的输入中最后一个交易日)收盘价的涨跌幅,设置其上限为0.3,下限为-0.3(当然,连续三个涨停板的涨幅会超过0.3,这里将其统一视作0.3)。之所以选择三个交易日之后的涨跌幅作为训练样本的输出,是因为我国股市是T+1操作规则,当日买入不可卖出,预测的稍微靠后一些可留有操作空间;再有就是一天的拉升/砸盘偶然性太大,不易预测,对稍微长期一点的状况进行预测有着更高的稳定性。

  归一化相关工作:因为神经网络激活函数的限制,需要在训练前将数据映射到0~1区间。本次试验中,对近两年的数据,获取其各项特征的最大值与最小值。设置归一化与函数,在样本拼接的同时将数据进行归一化。

样本 输入的归一化:

 1 def normalize_oneday(stockN,fdata,day):
 2     max_min = list(max_min_list[stockN])
 3     in_1 = (fdata.ix[day,1]-max_min[1])/(max_min[0]-max_min[1])
 4     in_2 = (fdata.ix[day,2]-max_min[3])/(max_min[2]-max_min[3])
 5     in_3 = (fdata.ix[day,3]-max_min[5])/(max_min[4]-max_min[5])
 6     in_4 = (fdata.ix[day,4]-max_min[7])/(max_min[6]-max_min[7])
 7     in_5 = (fdata.ix[day,5]-max_min[9])/(max_min[8]-max_min[9])
 8     in_6 = (fdata.ix[day,6]-max_min[11])/(max_min[10]-max_min[11])
 9     in_7 = (fdata.ix[day,7]-max_min[13])/(max_min[12]-max_min[13])
10     return [in_1,in_2,in_3,in_4,in_5,in_6,in_7]

样本 输出的归一化与反归一化:

def normalize_raise(volume):
    norm_value = (volume+0.3)/0.6
    if norm_value>1:
        norm_value = 1   #涨跌幅超过30%的都定义为 1或0
    elif norm_value<0:
        norm_value = 0
    return norm_value
def denormalize_raise(value):
    volume = value*0.6-0.3
    return volume

         设置滑动窗口sample_window =
[],每次遍历一行特征数据,归一化后插入窗口末尾,当窗口大小满50时,计算3天后涨跌幅,拼接出一个训练样本,并将sample_window中第一个交易日的值弹出。

1 normalized_daily_sample = normalize_oneday(stockN_list_str[i],fin_temp,day)
2 # TODO 给样本插入该日数据
3 sample_window.append(normalized_daily_sample)   #存入一个样本list,特征数为7,全部归一化完毕
4 if len(sample_window)==window_len:  # 窗口大小满50
5     #TODO 需要对涨幅进行归一化 暂定 30% TODO
6     raise_3days = normalize_raise(float(fin_temp.ix[day+3,8])/float(fin_temp.ix[day,8])-1.0)
7     samples.append([sample_window,raise_3days])
8     sample_window = sample_window[1:]

遍历完所有数据行后,获得数百个训练样本。并将训练样本转存为numpy.array格式以方便训练。

 注:跳点问题,具体分为除权(涨跌幅超过10%)与停盘(相邻交易日间隔超过10天)。对于跳点问题,我们判断其是否发生,一旦发生跳点,就清空sample_window,从下一个交易日重新开始计算样本输入,以杜绝样本输入中有跳点数据。

1 # 间隔日期大于10天,即day+3大于12天,判断为有停盘,不连续,或者涨跌幅异常(超过10.5%),不能作为训练样本序列, 
2 if int(diff/(24*3600))>12 or abs(raise_value)>10.5:  
3     sample_window = []

 

三.搭建模型

        
这里使用keras深度学习框架对模型进行快速搭建。建立Sequential模型,向其中添加LSTM层,设定Dropout为0.2,加入Dense层将其维度聚合为1,激活函数使用relu,损失函数定为交叉熵函数。之前也使用过传统的sigmoid作为激活函数,但经实验感觉效果不如relu。

1 model = Sequential()
2 model.add(LSTM(128, input_shape=(window_len,7), return_sequences=False))  # TODO: input_shape=(timesteps ,data_dim)
3 model.add(Dropout(0.2))
4 model.add(Dense(1))
5 model.add(Activation('relu'))
6 model.compile(loss='binary_crossentropy',optimizer='rmsprop',metrics=['accuracy'])

  模型搭建完毕,使用之前获得的数百个训练样本展开训练,并保存模型。

1 hist = model.fit(trainX,trainY,batch_size=1,epochs=50)
2 score = model.evaluate(trainX, trainY, batch_size=10)
3 if os.path.exists('./model/'+file_name[:-5]):
4     model.save('./model/'+file_name[:-5]+'/model_%s_%s.h5'%(window_len,date))  # HDF5 保存模型
5 else:
6     os.mkdir('./model/'+file_name[:-5])
7     model.save('./model/'+file_name[:-5]+'/model_%s_%s.h5'%(window_len,date)) 

 

四.效果展示

  最初的时候,我对所有的股票的训练样本堆叠到一起,训练出一个大模型(貌似当时有9万多个训练样本,整整训练了一天=,=),之后对每个股票都进行预测,企图找出次日涨幅最高的前5支股票。后来发现根本做不到……每支股票的操作规律都不一样,使用单个模型无法有效的把握个股的涨跌趋势。

  之后,我单独选了中国软件这个股票(这个票看起来像庄家主导的那种),对它单独进行分析。使用了一年半的交易数据作为训练集,共有293个训练样本,训练140个epoch。最后训练出模型对测试集中的60个测试样本进行验证。预测误差如下图。

 图片 50

 

其中前40个是训练集中的样本,我们使用其输入部分进行预测,发现预测结果贴合十分紧密;后60个是我们测试集的样本,我对其预测效果还是比较满意的,大跌、大涨基本都有预测到,除了第67到第75个点那一波大跌预测的不好。随后我使用模型进行模拟交易,设定初始资金两万元,在预测三天后会上涨时买入,预测三天后会下跌时卖出,均以收盘价为交易价格,买入时扣除万分之2.5的佣金。收益曲线如下,蓝色线条代表按模型进行交易的收益,绿色线条代表一直持有股票的收益。

图片 51

  可以看出,模型的预测效果还是不错的。尤其是开始的20多个点,能够较为准确的避开一波回调下跌。

  但我也知道,对模型进行验证的样本数量还是太少,又过了一个月,在额外收集了20个交易日的数据之后,我又对该样本进行了测试。

预测误差:

 图片 52

由上图可以看出,倒数20个交易日的这一波大涨幅,模型并没有能够预测到。

收益曲线:

 图片 53

  从上图可以看出,在紫色方框圈出来的地方,模型多次预测会有一波涨幅,但紧跟着又立马预测股价要跌,对股票进行了抛售,错过了这两次大涨的机会;在黄色方框圈出的地方,模型两次在顶点做出了准确的预测,精准抛售,躲过两次大跌。

 

经过股票数据的验证,使用LSTM-RNN来对股票进行预测具有一定的可行性,但效果不佳(要是效果好的话我估计也不会分享到网上,自己闷声发大财啦,哈哈~~~)。

 

[1]R. Akita, A. Yoshihara, T. Matsubara and K. Uehara, “Deep learning
for stock prediction using numerical and textual information,” 2016
IEEE/ACIS 15th International Conference on Computer and Information
Science (ICIS)
, Okayama, 2016, pp. 1-6.     
()

Post Author: admin

发表评论

电子邮件地址不会被公开。 必填项已用*标注