关闭

小波分析 + 支持向量机(SVM)预测股票涨跌幅的实现作者:k474905973

标签: MATLAB小波去噪
580人阅读 评论(0) 收藏 举报
分类:

量化投资领域,在做金融数据方面的预测。

做的这个策略来源于国信证券2010年中期策略会专题报告一篇名为《基于小波分析和支持向量机的指数预测模型》的研报(以下简称研报)。

策略思想:

1.先用小波分析对用于预测的数据集进行消噪处理

2.归一化消噪后的时间序列,求出新的股票指标,以备预测用

3.选择适当的核函数,对股票的涨跌情况Label进行预测,并求出支持向量机中的拉格朗日乘数alpha(有i个)和截距bias(一个)

4.根据alpha,bias和涨跌情况Label,结合核函数和支持向量机的高斯径向基函数,预测涨跌值z

5.用预测的涨跌值还原预测股票价格

下面详细讲解每一个步骤:

1.小波消噪

MATLAB自带小波分析工具箱,网上也有讲解,但是我在做的过程中也犯过迷糊,因此拿出来和大家分享一下。

假设我们要对成交量,收盘价,成交金额,最高价和最低价这五个指标进行消噪处理,并且用db4小波进行4层分解,那么代码应该是下面这样的:

%% 对每一个指标用db4小波执行4层小波分解
%对总成交量进行分解
[C_Volume, L_Volume] = wavedec(TotalVolumeIndex, 4, 'db4');
%对收盘价进行分解
[C_ClosePrice, L_ClosePrice] = wavedec(CloseIndex, 4, 'db4');
%对总成交金额进行分解
[C_Amount, L_Amount] = wavedec(TotalAmountIndex, 4, 'db4');
%对最高价进行分解
[C_HighPrice, L_HighPrice] = wavedec(HighIndex, 4, 'db4');
%对最低价进行分解
[C_LowPrice, L_LowPrice] = wavedec(LowIndex, 4, 'db4');

小波分析把原始的信号分解为两个部分:近似(Approximation)和细节(Detail),近似就是我们通常所说的信号的低频部分,而细节就是高频部分。信号的噪声通常包含在高频部分,而近似部分和原始的信号非常相似,但是我们又不能只保留低频部分对高频不管不问,因此我们可以只需要对高频部分进行消噪处理,然后再还原信号,代码如下(以收盘价为例,其他指标类似):

%% 从系数中4层近似(低频)和1,2,3,4层细节(高频)

%收盘价的4层近似和1,2,3,4层细节
A4_ClosePrice = wrcoef('a',C_ClosePrice, L_ClosePrice, 'db4', 4);
D4_ClosePrice = wrcoef('d',C_ClosePrice, L_ClosePrice, 'db4', 4);
D3_ClosePrice = wrcoef('d',C_ClosePrice, L_ClosePrice, 'db4', 3);
D2_ClosePrice = wrcoef('d',C_ClosePrice, L_ClosePrice, 'db4', 2);
D1_ClosePrice = wrcoef('d',C_ClosePrice, L_ClosePrice, 'db4', 1);

%% 对高频信息进行消噪处理

ClosePriceThreshold1 = thselect(D1_ClosePrice, 'sqtwolog');
ClosePriceThreshold2 = thselect(D2_ClosePrice, 'sqtwolog');
ClosePriceThreshold3 = thselect(D3_ClosePrice, 'sqtwolog');
ClosePriceThreshold4 = thselect(D4_ClosePrice, 'sqtwolog');
ClosePriceTR = [ClosePriceThreshold1,ClosePriceThreshold2,ClosePriceThreshold3,ClosePriceThreshold4];

可以从上面看到,近似只有第4层有,而细节在一二三四层都有,这是因为,小波消噪的原理图是这样的:

意思就是说,原始的信号被分解为了近似和细节两个部分,这个时候是在第一层,到了第二层,分解的就是第一层中的近似,而将第一层中的细节保留,到了第三层,同样,分解的是上一层的近似,保留上一层的细节,这样就会发现,细节和我们分解的层数一样多,而近似永远只有一个,而原始信号的大部分信息,都被保留在近似中。

消噪之后,就是恢复信号,函数和我所用到的属性及相应含义在下面的注释中都写清楚了,当然这个函数还有很多的属性选项,如需了解,敬请help MATLAB,作为简单的消噪处理,这些选项差不多基本够了。

%% 恢复去噪后的各项指标

%SORH是阈值选项,为s时选择软阈值,为h时选择硬阈值
SORH = 's';
%PERF0是恢复和压缩的范数百分比
%'lvd'为允许设置各层的阈值
%'gbl'为固定阈值
% 4为阈值的长度

[ClosePrice,CXC,LXC,PERF0,PERF2] = wdencmp('lvd',CloseIndex,'db4',4 ,ClosePriceTR ,SORH);

注意,小波分析工具箱里还有一组对应的函数,不记得叫什么名字了,反正可以实现和wrcoef一样的功能--从近似系数中提取近似和细节,因为当时是看了别人的博客,我以为所有的代码都需要,就写上去了,后来发现,实现的是一样的功能,只是略微有点差别,等我找到了那个函数再继续补充。

最后衡量一下去噪的效果,这段代码比较死,可以copy用,用多了就熟悉了。

%% 去噪效果衡量
%SNR越大效果越好,MSE越小越好
%获取各个部分的长度:理论上应该是一样长的
VolumeLength = length(TotalVolumeIndex);
ClosePriceLength = length(CloseIndex);
AmountLength = length(TotalAmountIndex);
HighPriceLength = length(HighIndex);
LowPriceLength = length(LowIndex);

x = CloseIndex;
y = ClosePrice;
SqureError = (CloseIndex-ClosePrice).^2;
SqureClosePrice = ClosePrice.^2;
ClosePriceToError = SqureClosePrice./SqureError;
RatioSum = sum(ClosePriceToError);
ErrorSum = sum(SqureError);
SNR =  10*log10(RatioSum);
MSE = ErrorSum/ClosePriceLength;
display(['SNR is:',num2str(SNR),';      MSE is:',num2str(MSE)])

最后,对比一下去噪前后的信号:

figure(2);
% subplot(2,1,1);
% plot(CloseIndex);
% title('原始收盘价曲线')
% subplot(2,1,2);
% plot(ClosePrice);
% title('消噪后的收盘价曲线')

2.归一化消噪后的时间序列,求出新的股票指标

归一化时间序列是都要做的,不管用什么方法,都不能让大的值比如成交量、成交金额在决策中抢了收盘价、开盘价等的风头,除非有这样的需求,不然就最好让这些指标都在同一起跑线上。

在这里,我用的是均值方差归一化方法,公式如下:

代码贴上,同样以收盘价为例,其他指标类似:

%对收盘价进行归一化
MeanClose = mean(ClosePrice);
VarClose = std(ClosePrice);
MeanTemp = zeros(size(MeanClose));
VarTemp = zeros(size(VarClose));
MeanTemp(:) = MeanClose;
VarTemp(:) = VarClose;
%根据归一化公式对收盘价进行归一化
ClosePriceNorm = (ClosePrice-MeanTemp)./VarTemp;

然后是准备支持向量机的输入,偷了个懒,和研报中用了相同的指标:


代码贴上:

%% 获取重要指标
for i = M+1:length(TotalVolume)
    VolumeIndex(i) = TotalVolume(i)/mean(TotalVolume(i-M:i-1));
    CloseIndex(i) = ClosePrice(i)/mean(ClosePrice(i-M:i-1));
    TradeAmountIndex(i) = TotalAmount(i)/mean(TotalAmount(i-M:i-1));
    MeanIndex(i) = mean(ClosePrice(i-M:i-1));
    RateChangeIndex(i) = (ClosePrice(i-1)-ClosePrice(i-M))/ClosePrice(i-M);
    HighIndex(i) = max(HighPrice(i-M:i-1));
    LowIndex(i) = min(LowPrice(i-M:i-1));
end

3.选择适当的核函数,对股票的涨跌情况Label进行预测,并求出alpha和bias

在做这一次策略之前,我一直非常不明白怎么对时间序列进行预测,我想还有很多刚刚接触机器学习的人和我有着同样的疑问,所以我简单说一下吧。

首先,我们要知道我们需要预测什么指标,需要用什么指标去预测,在这个例子里,我所用到的指标就是上面所说的CloseIndex,TradeAmountIndex等等,这些在教科书上,就体现为点的第N维坐标,把这些作为输入,再预测我们想要的值,例如明天的涨跌情况,就是这样的,非常简单。

在这里,我们计算的是M天以后的涨跌幅,涨跌幅的正负号值,就是涨跌情况啦,即Label!

%获取价格的涨跌情况
%yii为第M天之后的收盘价与当前i天的收盘价之差
y = zeros(size(ClosePrice));

for ii = 1: length(ClosePrice)-M
    y(ii) = ClosePrice(ii+M)-ClosePrice(ii);
end

%标记label
%价格上涨或持平记为1
%价格下跌记为-1
Label = zeros(size(y));
Label(find(y >= 0)) = 1;
Label(find(y < 0 )) = -1;

下面,我们将用MATLAB自带的svmtrain函数来预测股票的涨跌情况,即新的predictLabel。

在这里,训练的策略是这样的:训练N天的数据,预测N+1天到N+M天的数据的Label,然后窗口向前移动M个数据,直到全部数据都使用完毕。

for ii=1:M:(length(ClosePrice) - M - N - 1)
    %选取训练集和预测集
    trainData = DataMatrix(ii:ii+N-1,:);
    trainLabel = Label(ii:ii+N-1);
    predictData = DataMatrix(ii + N: ii + M + N -1,:); 
    %训练
    %用高斯径向基函数rbf进行训练
    struct = svmtrain(trainData, trainLabel, 'kernel_Function', 'rbf','rbf_sigma', sigma);%sigma 默认为1

    %从svm的结构体中提取alpha和bias
    alpha = struct.Alpha;
    bias = struct.Bias;
    SupportVectorIndex = struct.SupportVectorIndices;
    SupportVectors = struct.SupportVectors;
    %预测涨跌情况
    predictLabel = svmclassify(struct, predictData);
    %预测涨跌幅
    SupportLabel = trainLabel(SupportVectorIndex);
    z = cal_z(SupportVectors, SupportLabel, predictData, alpha, bias, sigma);
    z_predict(ii+N:ii+N+M-1) = z(:);
    %% 计算实际涨跌幅
    for jj = (ii+N):(ii+N+M-1)
        %预测的股票价格
        predictPrice (jj + M) = ClosePrice(jj) + z_predict(jj);    
        if jj == N + ii
            delta(jj + M) = ClosePrice(jj) + y(jj) - ClosePrice(jj -1);
            delta_predict(jj + M) = predictPrice (jj) - ClosePrice(jj - 1);
        elseif ((jj > N +ii) && (jj < N + M +ii) )
            delta(jj + M) = ClosePrice(jj) + y(jj) - (ClosePrice(jj - 1) + y(jj -1));
            delta_predict(jj + M) = predictPrice (jj) - predictPrice (jj - 1); 
        end        
    end
end

训练过程中,遇到了一个问题,就是如果我把训练集设置得过小或者预测集设置得过大,MATLAB都会报错,告诉我groups必须包含两个类别,我思考良久,发现并不是我的数据的问题,经过MATLAB群里一个同僚的提示,终于知道了答案,因为如果训练集过小,里面包含的Label就会只剩下一种,特别是股票数据,在短期内没有太大的变化,可能一直是1或者-1,这个时候,支持向量机就没法训练和预测,因此,如果下次有人还遇到这种情况,千万不要怀疑自己的数据有问题,把训练集改大一点就好了。

至此,这一步所需的工作已经完成,我们得到了我们想要的Label,alpha和bias。

4.根据alpha,bias和涨跌情况Label,结合核函数和支持向量机的高斯径向基函数,预测涨跌值z

研报告诉我们,svm预测出来的分类值代表了股票的涨跌情况,而没有被sign之前的函数值大概就是涨跌幅。

百度上说高斯径向基核函数的公式是这样的:

 k(||x-xc||)=exp{- ||x-xc||^2/(2*σ)^2) } 其中xc为核函数中心,σ为函数的宽度参数 , 控制了函数的径向作用范围。

这个宽度参数,就是上面这段代码中,svmtrain的最后一个参数,sigma。

这个过程相当于还原svmtrain的工作过程。

%% 用高斯径向基核函数计算z
[m1,n1] = size(testData);
[m2,n2] = size(SupportVectors);
z = zeros(m1,1);
for  ii = 1 : m1
    K = zeros(m1,1);
    for jj = 1: m2
        deltaRow = testData(ii , :) - SupportVectors(jj , :);
    end
    K(ii) = deltaRow * deltaRow';
    K = exp( K /(-(1*sigma)^2));
    save K.mat K
    save SupportLabel.mat SupportLabel
    save alpha.mat alpha
    z(ii) = (SupportLabel' * alpha) * K(ii) + bias;
    %注意运算技巧
end

然后,通过这个函数,我们连股票的涨跌值都预测出来了,用到的输入,都是第3步中的输出,MATLAB真心非常强大!

5.还原预测的股票价格

记得我们在之前定义的y(ii)是M天相对于ii天的股票涨跌幅,所以我们预测出来的z,也是M天之后的,要还原为当天的股价,加上M天之前的收盘价就好了,其实这部分的代码和第3部分的训练是挨在一起的,我再提出来让大家看清楚一点。

%预测涨跌幅
    SupportLabel = trainLabel(SupportVectorIndex);
    z = cal_z(SupportVectors, SupportLabel, predictData, alpha, bias, sigma);
    z_predict(ii+N:ii+N+M-1) = z(:);
    %% 计算实际涨跌幅
    for jj = (ii+N):(ii+N+M-1)
        %预测的股票价格
        predictPrice (jj + M) = ClosePrice(jj) + z_predict(jj);    
        if jj == N + ii
            delta(jj + M) = ClosePrice(jj) + y(jj) - ClosePrice(jj -1);
            delta_predict(jj + M) = predictPrice (jj) - ClosePrice(jj - 1);
        elseif ((jj > N +ii) && (jj < N + M +ii) )
            delta(jj + M) = ClosePrice(jj) + y(jj) - (ClosePrice(jj - 1) + y(jj -1));
            delta_predict(jj + M) = predictPrice (jj) - predictPrice (jj - 1); 
        end        
    end


然后我们的工作就都做完了,研报中作者说有延迟,但是预测得很准确,我做这个策略之前,对这个策略充满了信心。现在看做出来的结果也和研报中相似:

可是我做完之后,才发现问题还挺严重,因为在还原的时候,本来就是以M天以前的收盘价为基础加上来的,如果不能预测出和当天一样的价格或趋势,就说明Z没有预测到。我打算换神经网络做,下一篇博文发表用神经网络预测的结果。

这篇文章是MATLAB群里一个学弟要我写出来和大家分享的,在这过程中,遇到了很多新手都会遇到的问题,所以贴出来,让大家都能共同进步,也顺便纪念一下我第一次实现策略的时光。


对了,原文是用沪深300指数进行分析和预测的,由于我没有那个数据,我用的是SP500中随机选的一只股票的数据,而且这个数据里没有成交金额,所以成交金额也是用成交量代替的,也就是说我的策略里用了两次成交量,这也许也是策略不准的原因之一吧。

策略用到的数据:

http://download.csdn.net/detail/k474905973/7490371

策略源代码:(MATLAB)

http://download.csdn.net/detail/k474905973/7539409







0
0
查看评论

基于小波变换的时间序列预测,Python实现,来自雪球,

作者:量化哥-优矿Uqer 链接:https://xueqiu.com/4105947155/67920429?page=1 来源:雪球 基于小波变换的时间序列预测 本文的主题是考察小波变换在预测方面的应用。 思路将数据序列进行小波分解,每一层分解的结果是上次分解得到的...
  • zhaoyuxia517
  • zhaoyuxia517
  • 2017-09-16 19:17
  • 1917

小波分析 + 支持向量机(SVM)预测股票涨跌幅的实现

刚刚开始进入量化投资领域,最近在做金融数据方面的预测,用到了数据挖掘的
  • k474905973
  • k474905973
  • 2014-06-12 20:26
  • 6422

使用SVM预测大盘涨跌的简单策略

本策略是为了验证SVM对于大盘涨跌的预测是否有效,相比于纯随机策略,是否有明显的提高。 SVM模型用06~14年的数据训练,16年1月~12月的数据用来回测,这样是为了避免因为在模型中投入了现阶段的数据导致的过拟合。 第一次运算准确率为.66,不过个人认为这个准确率不一定能复现,所以做了Ac...
  • artemis_123
  • artemis_123
  • 2016-12-28 09:58
  • 3167

基于SVM的股票预测 Python实现 附Github

SVM 支持向量机 原理就不赘述了,其余的文章有讲过。SVM是一种十分优秀的分类算法,使用SVM也能给股票进行一定程度上的预测。 核心 因为是分类算法,因此不像ARIMA一样预测的是时序。分类就要有东西可分,因此将当日涨记为1,跌记为0,作为分类的依据。使用历史数据作为训练数据。 ...
  • jerry81333
  • jerry81333
  • 2016-12-30 21:32
  • 9904

SVM训练及预测过程

SVM训练及预测过程 http://blog.sina.com.cn/s/blog_65caa97801011fbi.html
  • zhangtaolmq
  • zhangtaolmq
  • 2014-08-15 19:46
  • 1310

时间序列(arima)+支持向量机(svm)+优化=组合预测

看见大家想学习组合预测,我今晚就准备加班,给大家上一个arima+svm的组合预测,有什么不足的请指出了,时间序列是一个大类,我今天主要是给大家展示的是最常用的arima.串联组合的原理都是这样的,前面用灰色预测或者时间序列或者回归等等,求出单预测,然后滚动残差,再把残差值与实际预测值相加的结果在拿...
  • u014356002
  • u014356002
  • 2016-11-14 20:10
  • 6044

支持向量机进行预测(SVM)Matlab版

  • 2010-01-27 02:20
  • 6KB
  • 下载

《简明Python教程》学习(一)

《简明Python教程》学习(一)一、 Python脚本开头为什么要写 #!/usr/bin/python1. 新建helloworld.py文件2. 内容print ‘helloworld’3. 运行python helloworld.py 4. 输出hell...
  • cainiao_learn
  • cainiao_learn
  • 2016-11-16 15:41
  • 1044

SVM预测

x=[1028.371654 959.1841538 956.84571 27.10416667 27.37333333 25.75 959.1841538 956.84571 939.7041246 ...
  • RicheyLee
  • RicheyLee
  • 2016-09-08 21:35
  • 966

基于SVM的回归预测分析

  • 2015-10-28 13:57
  • 218KB
  • 下载
    个人资料
    • 访问:17039次
    • 积分:337
    • 等级:
    • 排名:千里之外
    • 原创:6篇
    • 转载:53篇
    • 译文:1篇
    • 评论:7条
    最新评论