文件位置
/dzh2/data/sh/DAY.DAT
/dzh2/data/sz/DAY.DAT
/dzh2/data/hs/DAY.DAT
数据格式
说明:数据格式几乎与分析家相同
(1)、文件头部信息
起止地址 |
数据内容 |
数据含义 |
数据类型 |
00 - 03 |
F4 9B 13 FC |
文件标志 |
int |
04 - 07 |
00 06 00 00 |
未知 |
int |
08 - 0B |
00 00 00 00 |
保留 |
int |
0C - 0F |
97 04 00 00 |
证券总数 |
int |
10 - 13 |
00 18 00 00 |
总块数 |
int |
14 - 17 |
DB 17 00 00 |
已用块数 |
int |
(2)、股票数据分配记录,开始于0x0018h
起止地址 |
数据内容 |
数据含义 |
数据类型 |
18 - 21 |
31 41 30 30 30...FF |
证券代码 |
byte[10] |
22 - 25 |
B0 09 00 00 |
日线记录数 |
int |
26 - 57 |
00 00 BA 03...FF FF |
记录块号 |
word [25] |
(3)、股票数据记录块,开始于0x41000
起止地址 |
数据内容 |
数据含义 |
数据类型 |
41000 - 41003 |
80 47 B2 2B |
日期 |
int |
41004 - 41007 |
B9 1E 25 41 |
开盘价 |
float |
41008 - 4100B |
CD CC 4C 41 |
最高价 |
float |
4100C - 4100F |
EC 51 18 41 |
最低价 |
float |
41010 - 41013 |
9A 99 41 41 |
收盘价 |
float |
41014 - 41017 |
80 06 B2 47 |
成交量 |
float |
41018 - 4101B |
40 1C BC 4C |
成交金额 |
float |
4101C - 4101D |
00 00 |
上涨家数 |
word |
4101E - 4101F |
00 00 |
下跌家数 |
word |
注意:
1)、起止地址、数据内容为十六进制,数据类型为 Delphi 下之定义。
2)、从18h开始至40017h每64byte为一条股票数据分配记录,含义如上表18h - 57h所示;
3)、从41000h开始每8KB为一股票数据存储块,每个股票数据存储块共存储256条日线记录,每一条记录的长度为32 byte(含义如上表;上涨家数及下跌家数只对指数有效);
4)、从41000h开始的8KB(1024 * 8 = 8192)为第0号数据存储块,以后类推;
5)、系统对每个股票日线数据存储以存储块为单位进行分配。
记录块号计算方法:
char[0] = 0x00 第一个记录块起始地址为:41000h + 0x0000 * 0x2000 = 41000h;
char[1] = 0x03BA 第二个记录块起始地址为:41000h + 0x03BA * 0x2000 = 0x00077F78
6)、具体应用实例分析家数据管理程序。
7) 、日期字段的意义为:实际日期 = StrToDate(^1970-01-01^)+(日期字段 div 86400);即“日期字段”除以86400(60s * 60m * 24h = 86400s)所得数为实际日期距1970年01月01日的天数。
示例代码
示例:显示日线数据文件信息
说明:显示大智慧日线数据文件中头部信息、块索引信息、数据记录信息。
unit uDataBuffer;
interface
uses
SysUtils,Classes;
type
TCustomStringBuffer = class
private
FBuffer: PChar;
FBufferSize: Integer;
FContent: string;
function GetContent: string;
procedure SetBufferSize(Value: Integer);
procedure SetContent(const Value: string);
protected
procedure DoBufferChange; virtual;
procedure ClearBuffer; virtual;
public
constructor Create;
//---
function ReadFile(const AFileName: string): Boolean;
function SaveFile(const AFileName: string; const Append: Boolean = false):
Boolean;
//---
property Buffer: PChar read FBuffer;
property BufferSize: Integer read FBufferSize write SetBufferSize;
property Content: string read GetContent write SetContent;
end;
TRecordStream = class(TCustomStringBuffer)
private
FCount: Integer;
FDataSize: Integer;
function GetDatas(Index: Integer): Pointer;
procedure SetCount(const Value: Integer);
protected
procedure ClearBuffer; override;
procedure DoBufferChange; override;
//---
property Datas[Index: Integer]: Pointer read GetDatas;
property DataSize: Integer write FDataSize;
public
property Count: Integer read FCount write SetCount;
end;
function OpenToFile(const AFileName: string; const AMode: Integer; const AIsAppend: Boolean = false): integer;
function ReadFormFile(const AFileName: string): string;
function SaveToFile(const AFileName,AContent: string; const AIsAppend: Boolean
= false): Boolean;
implementation
function OpenToFile(const AFileName: string; const AMode: Integer; const AIsAppend: Boolean = false): integer;
const
CNT_OpenCount = 20;
CNT_OpenOutTime = 30;
//---
function _OpenWrite: integer;
var
i,AFileHandle: integer;
APath: string;
begin
if FileExists(AFileName) then
begin
for i := 0 to CNT_OpenCount do
begin
if AIsAppend then
AFileHandle := FileOpen(AFileName,fmOpenWrite or fmShareExclusive)
else
AFileHandle := FileCreate(AFileName);
if AFileHandle < 0 then
sleep(CNT_OpenOutTime)
else
Break;
end;
end
else
begin
APath := ExtractFilePath(AFileName);
if not DirectoryExists(APath) then
ForceDirectories(APath);
//---
AFileHandle := FileCreate(AFileName);
end;
//---
Result := AFileHandle;
end;
//---
function _OpenRead: integer;
var
i,AFileHandle: integer;
begin
Result := -1;
//---
if not FileExists(AFileName) then
Exit;
//---
for i := 0 to CNT_OpenCount do
begin
AFileHandle := FileOpen(AFileName,fmOpenRead or fmShareDenyNone);
if AFileHandle < 0 then
sleep(CNT_OpenOutTime)
else
Break;
end;
//---
Result := AFileHandle;
end;
begin
Result := -1;
//---
if Trim(AFileName) = '' then
Exit;
//---
if AMode = fmOpenWrite then
Result := _OpenWrite
else
Result := _OpenRead;
end;
function ReadFormFile(const AFileName: string): string;
var
AFileHandle,ABufferSize: integer;
begin
Result := '';
//---
AFileHandle := OpenToFile(AFileName,fmOpenRead);
if AFileHandle < 0 then
Exit;
//---
try
ABufferSize := FileSeek(AFileHandle,0,soFromEnd);
if ABufferSize = 0 then
Exit;
//---
SetLength(Result,ABufferSize);
//---
FileSeek(AFileHandle,0,soFromBeginning);
FileRead(AFileHandle,Pchar(Result)^,ABufferSize);
finally
FileClose(AFileHandle);
end;
end;
function SaveToFile(const AFileName,AContent: string; const AIsAppend: Boolean
= false): Boolean;
var
AFileHandle: integer;
begin
result := false;
//---
if Length(AContent) = 0 then
Exit;
//---
try
AFileHandle := OpenToFile(AFileName,fmOpenWrite,AIsAppend);
if AFileHandle < 0 then
Exit;
//---
try
if AIsAppend then
FileSeek(AFileHandle,0,soFromEnd)
else
FileSeek(AFileHandle,0,soFromBeginning);
FileWrite(AFileHandle,Pchar(AContent)^,Length(AContent));
finally
FileClose(AFileHandle);
end;
//---
Result := true;
except
on E: Exception do
begin
Result := false;
end;
end;
end;
procedure TCustomStringBuffer.ClearBuffer;
begin
FBufferSize := 0;
end;
constructor TCustomStringBuffer.Create;
begin
FBufferSize := 0;
end;
procedure TCustomStringBuffer.DoBufferChange;
begin
FBuffer := PChar(FContent);
end;
function TCustomStringBuffer.GetContent: string;
begin
if FBufferSize = 0 then
Result := ''
else
Result := FContent;
end;
function TCustomStringBuffer.ReadFile(const AFileName: string): Boolean;
begin
self.Content := ReadFormFile(AFileName);
Result := self.BufferSize > 0;
end;
function TCustomStringBuffer.SaveFile(const AFileName: string; const Append:
Boolean = false): Boolean;
begin
result := SaveToFile(AFileName,self.Content,Append);
end;
procedure TCustomStringBuffer.SetBufferSize(Value: Integer);
begin
FBufferSize := Value;
if FBufferSize < 0 then
FBufferSize := 0;
//---
if FBufferSize > 0 then
SetLength(FContent,Value);
//---
DoBufferChange;
end;
procedure TCustomStringBuffer.SetContent(const Value: string);
begin
FContent := Value;
FBufferSize := Length(FContent);
//---
DoBufferChange;
end;
procedure TRecordStream.ClearBuffer;
begin
inherited;
//---
FCount := 0;
end;
procedure TRecordStream.DoBufferChange;
//---
procedure _RefreshCount;
begin
FCount := FBufferSize div FDataSize;
if FDataSize * FCount <> FBufferSize then
self.ClearBuffer;
end;
begin
inherited;
//---
if FDataSize <= 0 then
self.ClearBuffer
else
_RefreshCount;
end;
function TRecordStream.GetDatas(Index: Integer): Pointer;
begin
Result := FBuffer + Index * FDataSize;
end;
procedure TRecordStream.SetCount(const Value: Integer);
begin
FCount := Value;
if FCount < 0 then
FCount := 0;
//---
self.BufferSize := FDataSize * FCount;
end;
end.
unit uDayData;
interface
uses
uDataBuffer;
const
CNT_BlockSize = 1024 * 8;
type
TFileHead_Day = packed record
FileSign: Integer; //--文件标志
FileInfo1: Integer;
FileInfo2: Integer;
StockCount: Integer; //--证券总数
BlockTotalCount: Integer; //--总块数
BlockUseCount: Integer; //--已用块数
end;
PTFileHead_Day = ^TFileHead_Day;
TIndexRecord_Day = packed record
StockCode: array[0..9] of char; //--证券代码
RecordCount: Integer; //--日线记录数
BlockIndexs: array[0..24] of word; //--记录块号
end;
PTIndexRecord_Day = ^TIndexRecord_Day;
TDataRecord_Day = packed record
rq: Integer; //--日期
kp: single; //--开盘
zg: single; //--最高
zd: single; //--最低
sp: single; //--收盘
sl: single; //--成交数量
je: single; //--成交金额
zj: Word; //--上涨家数
dj: Word; //--下跌家数
end;
PTDataRecord_Day = ^TDataRecord_Day;
{日线数据}
TStockDataStream_Day = class(TCustomStringBuffer)
private
FFileHead: TFileHead_Day;
FIndexCount: Integer;
FIndexSize: Integer;
FIndexStartAddress: Pchar;
FDataCount: Integer;
FDataSize: Integer;
FDataStartAddress: Pchar;
function GetDatas(Index: Integer): PTDataRecord_Day;
function GetHead: PTFileHead_Day;
function GetIndexs(Index: Integer): PTIndexRecord_Day;
protected
procedure ClearBuffer; override;
procedure DoBufferChange; override;
public
constructor Create;
//---
property Head: PTFileHead_Day read GetHead;
property Datas[Index: Integer]: PTDataRecord_Day read GetDatas;
property DataCount: Integer read FDataCount;
property Indexs[Index: Integer]: PTIndexRecord_Day read GetIndexs;
property IndexCount: Integer read FIndexCount;
end;
implementation
constructor TStockDataStream_Day.Create;
begin
inherited;
//---
FIndexSize := sizeof(TIndexRecord_Day);
FDataSize := sizeof(TDataRecord_Day);
end;
procedure TStockDataStream_Day.ClearBuffer;
begin
inherited;
//---
FIndexCount := 0;
FDataCount := 0;
end;
procedure TStockDataStream_Day.DoBufferChange;
const
CNT_IndexStartAddress = $00018;
CNT_DataStartAddress = $41000;
//---
function _ReadFileHead: Boolean;
begin
Result := self.BufferSize > CNT_IndexStartAddress;
if Result then
Move(self.Buffer^,FFileHead,SizeOf(FFileHead));
end;
//---
function _ReadIndex: Boolean;
begin
FIndexStartAddress := self.Buffer + CNT_IndexStartAddress;
FIndexCount := FFileHead.StockCount;
Result := self.BufferSize > CNT_IndexStartAddress + SizeOf(TIndexRecord_Day) * FIndexCount;
end;
//---
function _ReadData: Boolean;
begin
FDataStartAddress := self.Buffer + CNT_DataStartAddress;
FDataCount := (CNT_BlockSize * FFileHead.BlockUseCount) div SizeOf(TDataRecord_Day);
Result := self.BufferSize >= CNT_DataStartAddress + SizeOf(TDataRecord_Day) * FDataCount;
end;
begin
inherited;
//---
if FDataSize <= 0 then
self.ClearBuffer
else
begin
if not (_ReadFileHead and _ReadIndex and _ReadData) then
self.ClearBuffer;
end;
end;
function TStockDataStream_Day.GetDatas(Index: Integer): PTDataRecord_Day;
begin
Result := Pointer(FDataStartAddress + FDataSize * Index);
end;
function TStockDataStream_Day.GetHead: PTFileHead_Day;
begin
Result := @FFileHead;
end;
function TStockDataStream_Day.GetIndexs(Index: Integer): PTIndexRecord_Day;
begin
Result := Pointer(FIndexStartAddress + FIndexSize * Index);
end;
end.
unit Unit1;
interface
uses
Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms,
Dialogs,StdCtrls,ExtCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
ListBox1: TListBox;
GroupBox1: TGroupBox;
OpenDialog1: TOpenDialog;
RadioGroup1: TRadioGroup;
Panel1: TPanel;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
procedure ShowHqData(const AFile: string; const AListBox: TListBox);
public
procedure ShowData(const AFile: string; const AListBox: TListBox);
end;
var
Form1: TForm1;
implementation
uses uDayData;
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
SendMessage(ListBox1.Handle,LB_SetHorizontalExtent,2000,longint(0));
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
with self.OpenDialog1 do
begin
if Execute then
ShowData(FileName,ListBox1);
end;
end;
procedure TForm1.ShowData(const AFile: string; const AListBox: TListBox);
begin
case RadioGroup1.ItemIndex of
0: ShowHqData(AFile,AListBox);
end;
end;
procedure TForm1.ShowHqData(const AFile: string; const AListBox: TListBox);
var
AStream: TStockDataStream_Day;
//---
procedure _ShowHead;
begin
with AStream.Head^ do
AListBox.Items.Add(Format('文件标志:%d 股票数量:%d 总块数:%d 已用块数:%d', [FileSign,StockCount,BlockTotalCount,BlockUseCount]));
end;
//---
procedure _ShowIndex;
var
i,j: Integer;
AText: string;
begin
with AListBox.Items,AStream do
begin
Add('--------索引---------');
//---
for i := 0 to IndexCount - 1 do
begin
with Indexs[i]^ do
begin
AText := '';
for j := Low(BlockIndexs) to High(BlockIndexs) do
begin
if BlockIndexs[j] <> $FFFF then
AText := Format('%s %.2d', [AText,BlockIndexs[j]]);
end;
//---
Add(Format('%.3d 证券代码:%s 记录数量:%d 记录块号:%s', [i,StockCode,RecordCount,AText]));
end;
end;
end;
end;
//---
procedure _ShowData;
var
i,ABlockID,ACurBlockID: Integer;
AStartDate: TDate;
ACurDate: string;
begin
AStartDate := StrToDate('1970-01-01');
//---
with AListBox.Items,AStream do
begin
ABlockID := 0;
Add(Format('--------块%d---------', [ABlockID]));
//---
for i := 0 to DataCount - 1 do
begin
with Datas[i]^ do
begin
ACurBlockID := i * SizeOf(TDataRecord_Day) div CNT_BlockSize;
if ABlockID <> ACurBlockID then
begin
ABlockID := ACurBlockID;
Add(Format('--------块%d---------', [ABlockID]));
end;
//---
if rq > 0 then
ACurDate := DateToStr(AStartDate + rq div 86400)
else
ACurDate := '0';
Add(Format('%.3d %s 开%.2f 高%.2f 低%.2f 收%.2f 量%.2f 额%.2f 上%d 下%d', [i,ACurDate,
kp,zg,zd,sp,sl,je,zj,dj]));
end;
end;
//---
Add('*****************');
Add(Format('--------已用块%d---------', [ABlockID]));
end;
end;
begin
AStream := TStockDataStream_Day.Create;
try
with AListBox.Items do
begin
BeginUpdate;
Clear;
with AStream do
begin
if ReadFile(AFile) then
begin
_ShowHead;
_ShowIndex;
_ShowData;
end;
end;
EndUpdate;
end;
finally
AStream.Free;
end;
end;
end.