股票数据文件格式分析工具
基本说明
1、基本思路
(1)、股票数据文件一般是按照某种记录格式进行存储的。
如:
大智慧L2日线数据记录
TDataRecord_Day = packed record
rq: Integer; //--日期
kp: single; //--开盘
zg: single; //--最高
zd: single; //--最低
sp: single; //--收盘
sl: single; //--成交数量
je: single; //--成交金额
zj: Word; //--上涨家数
dj: Word; //--下跌家数
end;
通达信V6日线数据记录
TDataRecord_Day = packed record
date: Integer; //--日期
open: Integer; //--开盘
high: Integer; //--最高
low: Integer; //--最低
close: Integer; //--收盘
amount: single; //--成交金额
vol: Integer; //--成交数量
reservation: Integer; //--保留
end;
(2)、记录中的字段一般是word、int、float、char等基本类型。
2、分析步骤
(1)、读取源文件内容。
(2)、从指定位置处取出指定类型(如word、int、float、char等基本类型)的数据,判断数据是否与某个实际值相符。
(3)、依次执行第二步,以判断出记录中的每个字段。
(4)、根据字段值大致确定字段的含义。
(5)、确定记录的长度。
(6)、确定文件中附加信息的长度(有时程序会在文件头部和尾部附加一些描述或配置信息)。
(7)、根据分析出的记录格式编写测试程序。
示例代码
示例:分析股票数据文件记录格式
单元:uDataBuffer
备注:uDataBuffer单元代码在“大智慧Level2日线数据文件格式分析”文档中。
单元:Unit1
unit Unit1;
interface
uses
Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms,
Dialogs,StdCtrls,ExtCtrls,uDataBuffer;
type
TForm1 = class(TForm)
btnOpen: TButton;
OpenDialog1: TOpenDialog;
Memo1: TMemo;
GroupBox1: TGroupBox;
grpField: TGroupBox;
lstField: TListBox;
btnAnalyse: TButton;
edtPos: TEdit;
grpResult: TGroupBox;
lstResult: TListBox;
btnClear: TButton;
Splitter1: TSplitter;
btnSave: TButton;
GroupBox2: TGroupBox;
edtRecordLen: TEdit;
btnCalc: TButton;
Label1: TLabel;
procedure FormDestroy(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure btnAnalyseClick(Sender: TObject);
procedure btnCalcClick(Sender: TObject);
procedure btnClearClick(Sender: TObject);
procedure btnOpenClick(Sender: TObject);
procedure btnSaveClick(Sender: TObject);
procedure lstFieldDblClick(Sender: TObject);
procedure lstResultDblClick(Sender: TObject);
private
FStream: TCustomStringBuffer;
public
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
FStream := TCustomStringBuffer.Create;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
FStream.Free;
end;
procedure TForm1.btnOpenClick(Sender: TObject);
//---
function _ShowData(const AFile: string): string;
const
HEX: array[0..15] of char = ('0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F');
var
i,AStrPos: Integer;
pData: PByte;
AHex: string;
begin
Result := '';
//---
with FStream do
begin
if ReadFile(AFile) then
begin
pData := Pointer(Buffer);
//---
setlength(Result,BufferSize * 3);
//---
AStrPos := 1;
for i := 1 to BufferSize do
begin
Result[AStrPos] := HEX[(pData^ and $F0) shr 4];
inc(AStrPos);
Result[AStrPos] := HEX[(pData^ and $0F)];
inc(AStrPos);
Result[AStrPos] := ' ';
inc(AStrPos);
//---
inc(pData);
end;
end;
end;
end;
begin
with self.OpenDialog1 do
begin
if Execute then
begin
with Memo1.Lines do
begin
BeginUpdate;
Text := _ShowData(FileName);
EndUpdate;
end;
end;
end;
end;
procedure TForm1.btnAnalyseClick(Sender: TObject);
var
pData: PByte;
APos: integer;
s: string;
begin
pData := Pointer(FStream.Buffer);
//---
APos := strtointdef(edtPos.Text,0);
if APos < 0 then
APos := 0;
inc(pData,APos);
//---
with lstField.Items do
begin
Clear;
BeginUpdate;
//---
Add(format('2 SmallInt %d', [PSmallInt(pData)^]));
Add(format('4 Integer %d', [PInteger(pData)^]));
Add(format('8 Int64 %d', [PInt64(pData)^]));
Add(format('1 Byte %d', [PByte(pData)^]));
Add(format('2 Word %d', [PWord(pData)^]));
Add(format('4 LongWord %d', [PLongWord(pData)^]));
Add(format('4 Single %f', [PSingle(pData)^]));
Add(format('8 Double %f', [PDouble(pData)^]));
Add(format('1 Char %s', [PChar(pData)^]));
Add(format('2 WideChar %s', [PChar(pData)^ + PChar(integer(pData) + 1)^]));
//---
EndUpdate;
end;
end;
procedure TForm1.lstFieldDblClick(Sender: TObject);
begin
with lstField do
begin
if ItemIndex >= 0 then
lstResult.Items.Add(Items[ItemIndex]);
end;
end;
procedure TForm1.btnClearClick(Sender: TObject);
begin
lstResult.Items.Clear;
end;
procedure TForm1.btnSaveClick(Sender: TObject);
begin
with lstResult.Items do
if Count > 0 then
SaveToFile(format('%s%s', [ExtractFilePath(Paramstr(0)), 'Record.txt']));
end;
procedure TForm1.lstResultDblClick(Sender: TObject);
begin
with lstResult do
begin
if ItemIndex >= 0 then
lstResult.Items.Delete(ItemIndex);
end;
end;
procedure TForm1.btnCalcClick(Sender: TObject);
var
ALen: integer;
begin
ALen := strtointdef(edtRecordLen.Text,0);
if ALen < 1 then
exit;
//---
showmessage(format('总长度:%d 记录长度:%d 记录数量:%d 剩余长度:%d ',
[FStream.BufferSize,ALen,FStream.BufferSize div ALen,FStream.BufferSize mod ALen]));
end;
end.
窗体文件:
object Form1: TForm1
Left = 257
Top = 153
Width = 681
Height = 332
Caption = 'Form1'
Color = clBtnFace
Font.Charset = GB2312_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = '宋体'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
OnDestroy = FormDestroy
PixelsPerInch = 96
TextHeight = 12
object Splitter1: TSplitter
Left = 199
Top = 0
Height = 298
Align = alRight
end
object GroupBox1: TGroupBox
Left = 0
Top = 0
Width = 199
Height = 298
Align = alClient
Caption = '源文件'
TabOrder = 0
object Memo1: TMemo
Left = 2
Top = 58
Width = 195
Height = 238
Align = alBottom
TabOrder = 0
end
object btnOpen: TButton
Left = 54
Top = 18
Width = 75
Height = 25
Caption = '打开'
TabOrder = 1
OnClick = btnOpenClick
end
end
object grpField: TGroupBox
Left = 202
Top = 0
Width = 176
Height = 298
Align = alRight
Caption = '数据格式'
TabOrder = 1
object lstField: TListBox
Left = 2
Top = 58
Width = 172
Height = 238
Align = alBottom
ItemHeight = 12
TabOrder = 0
OnDblClick = lstFieldDblClick
end
object btnAnalyse: TButton
Left = 16
Top = 24
Width = 75
Height = 25
Caption = '分析'
TabOrder = 1
OnClick = btnAnalyseClick
end
object edtPos: TEdit
Left = 104
Top = 25
Width = 57
Height = 20
TabOrder = 2
Text = '0'
end
end
object grpResult: TGroupBox
Left = 378
Top = 0
Width = 174
Height = 298
Align = alRight
Caption = '结果'
TabOrder = 2
object lstResult: TListBox
Left = 2
Top = 58
Width = 170
Height = 238
Align = alBottom
ItemHeight = 12
TabOrder = 0
OnDblClick = lstResultDblClick
end
object btnClear: TButton
Left = 16
Top = 24
Width = 75
Height = 25
Caption = '清空'
TabOrder = 1
OnClick = btnClearClick
end
object btnSave: TButton
Left = 104
Top = 24
Width = 59
Height = 25
Caption = '保存'
TabOrder = 2
OnClick = btnSaveClick
end
end
object GroupBox2: TGroupBox
Left = 552
Top = 0
Width = 121
Height = 298
Align = alRight
Caption = '附加信息'
TabOrder = 3
object Label1: TLabel
Left = 24
Top = 40
Width = 48
Height = 12
Caption = '记录长度'
end
object edtRecordLen: TEdit
Left = 24
Top = 56
Width = 81
Height = 20
TabOrder = 0
Text = '0'
end
object btnCalc: TButton
Left = 24
Top = 88
Width = 75
Height = 25
Caption = '计算'
TabOrder = 1
OnClick = btnCalcClick
end
end
object OpenDialog1: TOpenDialog
Left = 136
Top = 16
end
end
示例:使用分析测试程序分析股票数据文件
说明:分析通达信日线文件/jcb_zxjt/T0002/cache/sz000005.day
步骤:
(1)、读取源文件内容。
(2)、设置数据分析“起始位置”为0,点击“分析”,从“分析结果列表”选出数值有意义(即类似于日期、开盘价等行情值)的类型,然后双击放入“记录格式结果列表”中。
(3)、依次执行第二步,以判断出记录中的每个字段。
(4)、根据字段值大致确定字段的含义。
4 Integer 1 未知
4 Integer 20090703 日期
4 Single 4.80 开
4 Single 5.26 高
4 Single 4.67 低
4 Single 5.12 收
4 Single 677758080.00 成交金额
4 Integer 134395414 成交量
4 Integer 0未知
4 Integer 20090706日期
4 Single 5.12开
(5)、根据“日期”字段的位置,确定记录长度为32字节。
(6)、根据记录长度和文件长度确定附加信息为文件头部的4个字节。