您的位置:首页 > 股票知识 > 股票投资策略 > 如何将数据分成多列_如何将数据分成训练集和测试集?

如何将数据分成多列_如何将数据分成训练集和测试集?

时间:2013-05-24   来源:股票投资策略   点击:

本例展示如何将数据分成训练集和测试集。我们将回测一个配对交易策略,在训练集上优化参数,在测试集上观察效果。

如何将数据分成训练集和测试集?

GLD代表黄金的现货价格,GDX是一揽子采金企业股票,两者的价格是高度相关的,故GLD和GDX可用于做配对交易。不过我要到第7章才会讲训练集上的协整分析,结果表明,GLD多头和GDX空头所形成的差价呈均值回归。通过训练集上的回归分析可得出GLD和GDX之间的对冲比率,并设定配对交易策略进出市场的阀值。从后面可以看到,阀值在训练集上的优化会改变策略在测试集上的业绩。(程序文件可从epchan. com/book/example3-6.m下载,数据文件为GLD. xls和GLD.xls。)程序使用滞后命令,将时间序列滞后一期,这在epchan.com/book中也能找到。还会使用“普通最小二乘法(OLS)”命令进行线性回归,在spatial-econometrics.com上可免费打包下载。

使用MATLAB

%清除工作空间已有变量

clear;

%将“GLD.xls”读入MATLAB

[num,txt]=xlsread("GLD");

%第一列(从第二行开始)是交易日,格式为mm/dd/yyyy

tdayl=txt(2:end,1);

%将时间格式转化为yyyymmdd

tdayl=…

datestr(datenum (tdayl,"mm/dd/yyyy"),"yyyymmdd");

%将数据字符串转化为单元型变量,再转化为数值型变量

tdayl =str2double(cellstr(tdayl));

%最后一列是调整后收盘价

adjclsl=num(:,end);

%读入“GDX. x1s”

[num,txt]=xlsread("GDX");

%第一列(从第二行开始)是交易日,格式为mm/dd/yyyy

tday2=txt(2:end,1);

%将时间格式转化为yyyymmdd

tday2=…

datestr(datenum (tday2,"mm/dd/yyyy"),"yyyymmdd");

%将数据字符串转化为单元型变量,再转化为数位型变量

tday2=str2double(cellstr(tday2));

%最后一列是调整后收盘价

adjcls2=num(:,end);

%找到两组数据的交集并按升序排列

[tday,idxl,idx2]=intersect(tdayl,tday2);

cll=adjclsl(idxl);

c12=adjcls2(idx2);

trainset=1:252;%定义训练集一标

%定义测评集下标

testset = trainset(end)+1:length(tday);

%用回归函数计葬得到对冲比率

results=ols(cll (trainset),c12(trainset));

hedgeRatio= results. beta;

%差价=GLD一对冲比率*GDX

spread=cll一hedgeRatio*c12;

plot(spread(trainset));

figure;

plot(spread(testset));

figure;

%训练集平均差价

spreadMean= mean(spread(trainset ));

%训练集差价标准差

spreadStd =std(spread(trainset));

%差价标准化(用z-scores方法)

zscore = (spread一spreadMean). /spreadStd;

%在组合价值向下跌破2倍标准差时,购买此差价组合

longs=zscore<=一2;

%当组合价值上升超过2倍标准差时,做空该差价组合

shorts=zscore>=2;

%当组合价值回到1倍标准差以内时,清仓

exits=abs(zscore) <=1;

写初始化头寸数组

positions=NaN(length Way),2);

%多头入市

positions(shorts,:)= repmat[一1 1],[length(find(shorts))1]);

%空头入市

positions(longs,:)=repmat([1一1],[length(find(longs))1]);

%清仓

positions(exits,:)=zeros(length(find(exits)),2);

%确保继续持仓,除非出现清仓信号

%positions= fillMissingData(positions);

cl=[cllc12];%合并两个价格序列

dailyret=(cl一lagl(cl))./lagl(cl);

pnl=sum(lagl(positions).*dailyret,2);

%训练集的夏普比应该足2.3

sharpeTrainset=…

sgrt(252)*mean(pnl(trainset(2:end)))./std(pnl(trainset(2:end)))

%测评集的夏普比应该是1.5

sharpeTestset =sgrt(252)*mean(pnl(testset))./std(pnl(testset))

plot(cumsum(pnl(testset )));

sharpeTestset = sqrt(252)*mean(pnl(testset))./std(pnl(testset))

plot(cumsum(pnl(testset)));

%保存头寸文件以便检查数据先窥偏差

save example3-6-positions positions;

文件lagl. m:

function y=lagl(x)

%y=lag(x)

if(isnumeric(x))

%第一个元素填充为NaN

y=[NaN(1,size(x,2));x(1:end一1,:)];elseif(ischar(x))

%第一个元素填充为”

Y=[repmat(””,[1 size(x,2)]);x(1:end一1,:)];else error("Can only be numeric or char array’);

End

此配对交易策略在训练集和测试集上的夏普比率都很高,因此可认为它是无数据迁就偏差的。但也许还有进一步改进的空间。若把建仓阀值改为1倍标准差、清仓阀值改为0.5倍标准差,训练集上的夏普比率会上升到2.9 ,测试集上的夏普比率会上升到2.1。显然,这一阀值集更佳。

不过,在训练集上进行参数优化也许会降低测试集上的业绩。这种情况下,应选择使得训练集和测试集上的业绩结果都较好(也许不是最好)的参数集。

我没有将交易成本考虑在内(下一节会讨论交易成本)。读者可以自己做练习。由于这一策略不是频繁交易,因此,交易成本对所得的夏普比率影响并不大。

为观察这一策略是如何工作的,读者可参见所显示的差价。你将看到差价走势呈现出很明显的均值回归。因此,不断地低买高卖是很管用的。

最后,还要检测任何可能的数据前视偏差。在上面的MATLAB代码“cl2=adjcls2 (idx2);”之后,添加以下代码。

%将最近的交易日数据移除掉

cutoff=60;%移除最近60天的数据

tday(end一cutoff+l:end,:)=[];

cll(end一cutoff +l:end,:)=[];

c12(end-cutoff+1:end,:)=[];

将以下代码放在上面MATLAB程序的结尾,取代“save example3_6_positions positions”。

%检测数据先窥偏差的第二步

oldoutput=load (’example3-6-positions");

oldoutput. positions(end一cutoff+1:end,:)=[];

if (any( positions~=oldoutput. positions))

fprintf(1."Program has look-forward-bias!\n")

End

将新的代码保存为“example3 - 6 - 1. m”并运行,你会发现“Program has look-forward-bias”语句不会被打印出来,这说明算法通过测试了。


推荐内容

推荐文章

栏目导航

友情链接

网站首页
早报
原创
名家
新闻
学堂
期货
理财
外汇
炒股软件
股票知识
K线图
平均线
分时图
短线炒股
MACD
涨停板
强势股
热门资讯

copyright 2016-2018 股民股票网保留所有权 京ICP备16025527号 免责声明:网站部分内容转载至网络,如有侵权请告知删除