通达信具有强大的板块处理能力,并且一些板块数据是动态更新的,做股票量化设计的时候,借助通达信的板块动态文件,取到事半功倍的效果,本文用实例说明如何利用通达信板块数据动态更新到自己的板块库。
一、 通达信的板块板块文件及其数据格式;
通达信针对股票的常用板块有风格板块、概念板块、指数板块,分别对应的文件为block_fg.dat;block_gn.dat;block_zs.dat
存储路径为 \T0002\hq_cache
三个板块的数据格式均为二进制文件,并且格式相同:
文件存储格式:
文件头:384字节
板块个数:2字节
各板块数据存储结构(紧跟板块数目依次存放),
每个板块占据的存储空间为2813个字节,可最多包含400只个股
板块名称:9字节
该板块包含的个股个数:2字节
板块类别:2字节
该板块下个股代码列表(连续存放,直到代码为空)
个股代码:7字节
二、 通达信板块数据更新频率;
通达信对不同的板块更新的频率不同,具体可以参考通达信的红宝书文件。为简单期间,本地数据库建议每天更新,更新时间设在上午9:00之后。
三、 Matlab对板块数据的储存格式
用table格式,table包括四个字段,分别为Date,fg,gn,zs;对应更新时间,风格板块,概念板块和指数板块三个板块类别。存储格式为N*2的元胞数组,N为该类别的板块数。
四、 自动更新设置
根据上交所交易日戳,如果table中的最后更新时间小于上交所日戳的最后时间,则自动更新。并且将自动更新的判断单独设立函数。在其他需要更新的地方也可正常调用。比如个股日线数据更新。
程序代码附后,剪贴板可能会有少数字符不能直接执行,需要修改。
网友如有更好优化,欢迎留言。
functionreadblock();
%% 批量读入通达信板块数据到表格
% 读入的板块文件分别为:block_fg.dat(风格板块);block_gn.dat(概念板块);block_zs.dat(指数板块)
% 文件位于 ‘C:\new_jyqyb\T0002\hq_cache’目录下;
% 存储格式为表,表的域名分别为:日期,风格板块,概念板块,指数板块
% 后面的数据域为元胞数组,{nCount,nLevel,nIndexOffset,blName,blstocks},
% 分别对应的说明为: {板块数,版块分类,板块指针,板块名称,成分代码};
% 根据通达信的定义,有些板块成分股有固定的调整周期,所以为确保数据完整性,
% 板块数据也需要每天更新。
blockFile = ['block_fg.dat';'block_gn.dat';'block_zs.dat'];
blockNmae = ['风格板块';'概念板块';'指数板块'];
blockPathin = 'C:\new_jyqyb\T0002\hq_cache' ;
blockPathout = 'D:\Stock\Data';
blockFileout = 'block.mat';
fo = [ blockPathout,'\',blockFileout];
if ~exist(fo,'file') %判断板块数据表是否存在,
block = table;
needUp = 1;
else
load(fo) %打开存在的板块数据表;
if ~isempty(block)
bd=block.Date(end);
if ~(strcmp(class(bd),'char'))
blockoldDate = char(bd);
else
blockoldDate = bd;
end
needUp = Needupdata(blockoldDate);
else
needUp = 1;
end
end
while needUp == 1 %如果需要更新
bnum = length(blockFile(:,1));
for bln = 1:bnum
bf = [blockPathin,'\',blockFile(bln,:)];
blocktemp(bln,:) ={ readoneblock(bf)};
end
D1 = datestr(now,'yyyy-mm-dd HH:MM:SS');
blocktabletemp = cell2table({D1,blocktemp(1,1),blocktemp(2,1),blocktemp(3,1)},...
'VariableNames',{'Date','fg','gn','zs'});
block = [block;blocktabletemp];
save (fo,'block');
needUp = 0;
end;
function[nnblodk] = readoneblock(blockfilename)
%% 取通达信板块数据
% 概念板块
%{
数据结构
文件存储路径:tdx\T0002\hq_cache\block.dat
文件存储格式:
文件头:384字节
板块个数:2字节
各板块数据存储结构(紧跟板块数目依次存放),
每个板块占据的存储空间为2812个字节,可最多包含399个个股
板块名称:9字节
该板块包含的个股个数:2字节
板块类别:2字节
该板块下个股代码列表(连续存放,直到代码为空)
个股代码:7字节
%}
fngn = blockfilename;
fid = fopen(fngn,'r','n','gb-2312');
szVersion = char(fread(fid,64,'char'))'; %文件版本信息
szVersion(abs(szVersion)==0)=[]; %切除后面的无效字符
fseek (fid,384,'bof');
nIndexOffset = fread(fid,1,'uint16'); %板块个数
for i = 1:nIndexOffset
fseek (fid,386+(i-1)*2813,'bof');
ju = 1;
cc = char(fread(fid,1,'char'));
for k = 1:8
while ju
cc1 = char(fread(fid,1,'char'));
if abs(cc1) > 0
cc = [cc,cc1];
else
ju = 0;
end
end
end
szName(i,:) ={ cc };
fseek (fid,395+(i-1)*2813,'bof');
nCount(i) = fread(fid,1,'uint16');
%fseek (fid,397+(i-1)*2813,'bof');
nLevel(i) = fread(fid,1,'uint16');
sztemp = [char(fread(fid,[7,400],'char'))];
sztemp = sztemp';
sztemp(int16(nCount(i)+1):end,:)=[];
sztemp(:,7)=[];
sz(i,1) = {sztemp};
end;
nnblodk = [szName,sz];
fclose(fid);
clear nCount nLevel nIndexOffset blName blstocks cc* i ju k sz* ans fngh;
function [ Needs_updating] = Needupdata( endDate,cStock )
%% 根据给定的日期,确定数据是否需要更新,这里约定的输入参数格式为 ‘yyyy-mm-dd HH:MM:SS’
% 输出值为 逻辑型,1表示需要更新;0表示不需要;
% 原理: 1、取交易所交易日戳数据
% 2、得到最后一个交易日期,约定的更新日期为每天收盘后2小时;
% 3、如果最后更新时间小于最后一个交易日的;
% 4、默认为大盘或板块类,如果指定cStock,则取对应的股票交易日戳;
load My % My储存登陆信息’
ret = gm.InitMD(My_username, My_password,1);
if nargin<2
cStock = 'SHSE';
else
if length(cStock)>6
cStock = str2symbol(cStock(end-5:end)) ;
end
end
start_time = datestr(datenum(today)-300,'yyyy-mm-dd');
end_time = datestr(today,'yyyy-mm-dd');
tradedate = gm.GetCalendar( cStock, start_time, end_time );
td1 = char(tradedate.strtime(end));
td = [td1(1:10),' 09:01:00'];
if length(endDate)==10
endDate = [endDate,' 00:00:00'];
else
if datenum(endDate,'yyyy-mm-dd HH:MM:SS')'yyyy-mm-dd HH:MM:SS')
Needs_updating = 1;
else
Needs_updating = 0;
end;
end;
function [symb_11] = str2symbol(str6)
%% 股票代码转化为掘金量化代码’
if strcmp(str6(1),'6')
symb_11 = ['SHSE.',str6];
else
symb_11 = ['SZSE.',str6];
end