豆粕、白糖期货涨跌幅的可视化分析
在之前的一篇文章中,也就是《matlab 从 wind 量化借口获取数据》 中已经介绍了如何获取数据,现在要对已经获取的数据进行一些基础的分析。
涨跌幅的统计
首先对涨跌幅进行统计。交易员要求统计的是开盘收盘的涨跌幅,也就日频率吧。当然,这里的日不是指交易日而是每个开收盘。交易员要求将日盘和夜盘分开然后按照时间串联起来。wind 上是没有提供这样频率的一个数据的。所以在之前这文章中我们提取数据的频率是 30 分钟的,然后自己从 60 分钟的数据中提取出开收盘的价格。
当然,你可能会奇怪。既然只要开盘和收盘那数据中为什么有个涨跌幅呢?因为我不知道 wind 中这个涨跌幅是怎么定义的,所以我想看一下 wind 自带涨跌幅的意思,所以特别提取出来。事后证明这个字段就是代表每个 K 线的涨跌幅。
那我们要得到涨跌幅必须自己计算。如何计算呢?我们先提取特点的时间点的 K 线。这个涨跌幅是这么定义的 (开盘-收盘) / 收盘。因此需要早上 9 点的开盘价,下午 3 点的收盘价。晚上 9 点的看盘价,晚上 11:30 的收盘价。但是如果认真观察会发现 wind 取的数据实在奇怪,有很多没有交易的时段也有数据,真是另人伤心,行业老大水平也如此另人堪忧,还是得自己搞数据库啊。所以,我再认真比对了 K 线图后取的 K 线是 9:30 ,15:00,12:30,23:30 时刻的。先看代码吧:
function future = calcdata(future)
% 传入参数和传出参数都为结构体future
name = fieldnames(future);
% 有np个期货品种
np = length(name);
% 需要的时间点
do = 930; dc = 1500;
no = 2130; nc = 2330;
for j = 1:np
% t = datestr(future.SR801.time);
% t = cellstr(t);
eval(['t = future.',name{j},'.time;']);
tv = datevec(t);
tnum = tv(:,4)*100 + tv(:,5);
ido = tnum == do;
idc = tnum ==dc;
ino = tnum == no;
inc = tnum == nc;
% % id1(find(id1 == 1,1)) = 0;
% % id2(find(id2 == 1,1)) = 0;
% tdo = t(ido);
% tdc = t(idc);
% tno = t(ino);
% tnc = t(inc);
% ind = ido + idc + ino + inc;
% ind = logical(ind);
% nt = t(ind);
id = ido + inc;
in = ino + idc;
id = logical(id);
in = logical(in);
% dt 和 nt 即日夜盘的时间,以便与核对是否计算错误
dt = t(id);
nt = t(in);
% 这里定义日盘涨跌幅为日盘开盘减夜盘收盘
% 夜盘涨跌幅为夜盘开盘减日盘收盘
% 我们通过 id 和 in 这两个下标剥离出了日夜盘涨跌的索引
% ld 和 ln 记录长度
ld = length(dt);
ln = length(nt);
% 找出日盘和夜盘涨幅在整个时间序列中的位置
iid = find(id ==1);
iin = find(in ==1);
% 计算日盘涨跌幅
n = 3:2:ld;
m = 0;
pd = nan(length(n),1);
pdt = nan(length(n),1);
% 将pd重新赋值为[pdt pd]
for i = n
m = m + 1;
pd(m) = (future.SR801.data(iid(i),1) - future.SR801.data(iid(i-1),2)) / future.SR801.data(iid(i-1),1);
pdt(m) = t(iid(i));
end
% 百分化
pd = pd * 100;
pd = [pdt pd];
% 夜盘
% 计算日盘涨跌幅
n = 2:2:ln;
m = 0;
pn = nan(length(n),1);
pnt = nan(length(n),1);
for i = n
m = m + 1;
pn(m) = (future.SR801.data(iin(i),1) - future.SR801.data(iin(i-1),2)) / future.SR801.data(iin(i-1),1);
pnt(m) = t(iin(i));
end
% 百分化
pn = pn * 100;
pn = [pnt pn];
% 将pd和pn写入到future中
eval(['future.',name{j},'.pd=pd;']);
eval(['future.',name{j},'.pn=pn;']);
end
end
我们通过 for 循环都对结构体的每个期货品种进行循环操作。也就是所计算涨跌幅的算法是通用的。首先将时间进行向量化处理,得到我们感兴趣的数值化的时间,比如 930.然后生成逻辑向量以标记我们需要的时间点。然后通过索引分开日夜盘,之后根据实际情况设计算法计算涨跌幅。最后将计算的数据重新写入到 future 中。
涨跌幅的可视化
统计出了涨跌幅自然要考虑如何展示,以便更好地分析。我们可以做一些基础的描述性统计。这里我机智的分开了日夜盘,接下来的数据分析中都有分日盘、夜盘还有日夜盘,这个日夜盘就是将日盘和夜盘合并的数据。
先描出数据的散点图,然后利用饼图和直方图进行初步统计。
function plotfuture(future)
name = fieldnames(future);
np = length(name);
for i = 1:np
eval(['p=future.',name{i},';']);
pa = catdn(p.pd,p.pn);
% 统计
mua = mean(pa(:,2));
sigmaa = std(pa(:,2));
mina = min(pa(:,2));
maxa = max(pa(:,2));
f1 = figure;
f1.Units = 'normalized';
f1.Position = [ 0.0847 0.0544 0.8194 0.8033];
% a1 = axes('Position',[0.05 0.05 0.8 0.75]);
plot(pa(:,1),pa(:,2),'r--*');
a1 = gca;
a1.Position = [0.16 0.11 0.8 0.82];
hold on
l1 = line([pa(1,1) pa(end,1)],[mua mua]);
l1.Color = 'b';
l1.LineWidth = 1;
l2 = line([pa(1,1) pa(end,1)],[mua+2*sigmaa,mua+2*sigmaa]);
l2.Color = 'g';
l2.LineWidth = 1;
l3 = line([pa(1,1) pa(end,1)],[mua-2*sigmaa,mua-2*sigmaa]);
l3.Color = 'g';
l3.LineWidth = 1;
legend('涨跌','均值','mu+2*sigma','mu-2*sigma');
datetick('x',1);
xtickangle(50);
axis tight
title([name{i},'合约日夜盘合并的情况']);
hold off
% 画出统计量
t1 = uitable(f1,'data',[mua;sigmaa;mina;maxa]);
t1.Units = 'normalized';
t1.Position = [0 0.4 0.135 0.14];
t1.ColumnName = {'值'};
t1.RowName = {'mu','sigma','min','max'};
tick = 0.2;
newsort(pa,tick,name{i},1)
%%
f2 = figure;
f2.Units = 'normalized';
f2.Position = [ 0.0847 0.0544 0.8194 0.8033];
% 统计
pd = p.pd;
pn = p.pn;
mud = mean(pd(:,2));
sigmad = std(pd(:,2));
mind = min(pd(:,2));
maxd = max(pd(:,2));
% 统计
mun = mean(pn(:,2));
sigman = std(pn(:,2));
minn= min(pn(:,2));
maxn = max(pn(:,2));
subplot(2,1,1);
plot(pd(:,1),pd(:,2),'r--*');
datetick('x',1,'keeplimits');
title([name{i},' 合约日盘涨跌情况']);
a2 = gca;
a2.Position = [0.16 0.56 0.8 0.341];
axis tight
subplot(2,1,2);
plot(pn(:,1),pn(:,2),'r--*');
datetick('x',1,'keeplimits');
title([name{i},' 合约夜盘涨跌情况']);
axis tight
a3 = gca;
a3.Position = [0.16 0.11 0.8 0.341];
td = uitable(f2,'data',[mud;sigmad;mind;maxd]);
td.Units = 'normalized';
td.Position = [0 0.6 0.135 0.14];
td.ColumnName = {'值'};
td.RowName = {'mu','sigma','min','max'};
tn = uitable(f2,'data',[mun;sigman;minn;maxn]);
tn.Units = 'normalized';
tn.Position = [0 0.3 0.135 0.14];
tn.ColumnName = {'值'};
tn.RowName = {'mu','sigma','min','max'};
newsort(pd,tick,name{i},2)
newsort(pn,tick,name{i},3)
end
end
这整个的函数还是以 future 为操作对象。可以看到调用了 catdn 这个函数。该函数代码如下:
function dn = catdn(d,n)
% 该函数把日盘的涨跌幅和夜盘的涨跌幅拼接起来
dnt = [d(:,1);n(:,1)];
[dnt,ind] = sort(dnt);
dn = [d(:,2);n(:,2)];
dn = dn(ind);
dn = [dnt dn];
end
也就是说这个函数得出了日夜盘的涨跌幅。然后统计最大值、最小值、方差、均值。然后进行绘图,本来应该很简单。但是可以看到代码比较多,这是因为对图形进行了一些具体的调整以便与观察,这就不详细解释。还有最后还调用了 newsort 函数,这个函数的作用是绘制饼图和直方图。代码如下:
function newsort(p,tick,name,c)
% 该函数对涨跌幅进行分类,并且绘制饼图
% p 为要分类的数据,而 tick 为分类的尺度
% name 合约名
% c 取值为 1 2 3,分别代表日夜盘,日盘,夜盘
if c == 1
addname = '日夜盘';
elseif c == 2
addname = '日盘';
else
addname = '夜盘';
end
p = p(:,2);
np = abs(p);
maxp = max(np);
n = ceil(maxp/tick);
edges = tick * ones(n,1);
edges = cumsum(edges)';
edges = [0 edges];
vnp = discretize(np,edges);
% 对绝对值序列绘图
% 统计np中各分类的个数
str_vnp = nan(size(vnp));
for i = 1:n
str_vnp(vnp == i) = tick*i;
end
str_vnp = num2str(str_vnp);
str_vnp(:,end+1) = '%';
str_vnp = cellstr(str_vnp);
str_vnp = categorical(str_vnp);
f1 = figure;
f1.Units = 'normalized';
f1.Position = [0.1 0.05 0.8 0.8];
subplot(2,2,1);
pie(str_vnp);
title([name,addname,'涨跌幅绝对值饼图']);
a1 = gca;
a1.Position = [0.05 0.5 0.25 0.5];
%% 绘制直方图
subplot(2,2,2);
histogram(str_vnp);
title([name,addname,'涨跌幅绝对值直方图']);
a2 = gca;
a2.Position = [0.5 0.55 0.45 0.4];
%% 对原始序列绘图
len = length(p);
vp = nan(len,1);
edge_n = 0.2 * ones(1,n);
edge_n = cumsum(edge_n);
edge_n = fliplr(edge_n);
edges = [-edge_n edges];
vp = discretize(p,edges);
str_vp = nan(size(vp));
for i = 1:2*n
if i <= 4
str_vp(vp == i) = edges(i);
else
str_vp(vp == i) = edges(i+1);
end
end
str_vp = num2str(str_vp);
str_vp(:,end+1) = '%';
str_vp = cellstr(str_vp);
str_vp = categorical(str_vp);
subplot(2,2,3);
pie(str_vp);
title([name,addname,'涨跌幅原始值饼图']);
a3 = gca;
a3.Position = [0.05 0.04 0.25 0.5];
%% 绘制直方图
subplot(2,2,4);
histogram(str_vp);
title([name,addname,'涨跌幅原始值直方图']);
a4 = gca;
a4.Position = [0.5 0.05 0.45 0.4];
end
这里要批评一下 matlab 自带的函数绘制饼图和直方图效果实在不敢恭维,费了好大的劲才调整到一个比较恰当的效果。这边值得一提的是这个 categorical 变量类型。这是为了在饼图中比较好的标上百分比才用的这个新的变量类型。其实费了很大的劲,也就是说这个变量类型 matlab 还有很大的改进空间。
很有意思,我之前在公司电脑运行还正常。但是这次我在版本上运行还出现了错误提示:
这估计是我笔记本性能太低的缘故。
内存已经不足了,还是应该努力赚钱改善生活。
结果展示
我们的 future 中一共有 6 个品种的数据,每个品种这里有产生 5 张图,因此一共有 30 张图。这里仅展示一个品种的图,而至于图片中所体现出来的信息就很值得深入挖掘了。
可以看到,图片的显示效果不好。其实我之前是在公司 27 寸的显示器上调整的,笔记本屏幕只有 14 寸,所以显示效果不好。大家如果屏幕够大,相信效果会很好。
这里的百分比已经叠住了,惨不忍睹。努力赚钱啊,年轻人。