線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:3762
推到 Plurk!
推到 Facebook!

为什么我的循环的速度很慢?有什么办法提高速度,代码如下。

答題得分者是:jow
pung4pung
一般會員


發表:8
回覆:8
積分:3
註冊:2007-10-14

發送簡訊給我
#1 引用回覆 回覆 發表時間:2007-11-30 21:29:58 IP:58.248.xxx.xxx 訂閱
速度太慢,有什么好办法呢??ReadedData[7][1000]约为7,1000的二维数组。循环计算约为1400次。

[code delphi]
{*功能:读取通达信日线数据

*}
unit DayDataAnys;

interface

uses
SysUtils,Dialogs,Math;

const
RECORD_LENGTH=32;
RECORD_FIELD_LENGTH=4;
Type
TArrayOfSingle=Array of Single;
TReadedData=Array of Array of LongWord;
TArrayOfString=array of string;
TBollRec=packed record
Upper:Single;
Mid:Single;
Lower:Single;
b:Single;
width:Single;
end;
TBollRedArray=array of TBollRec;

TDayData=class(TObject)
private
FFileName:String;
CanDo:Boolean;

Protected
Procedure CanDoTest;

Public
DayCount:Integer;

Function ReadData:TReadedData;
Function GetClosePrice:TArrayOfSingle;
function CalMA(N:Integer):TArrayOfSingle;
function CalBoll(N:Integer;P:Single):TBollRedArray;
function CalYiJin:TArrayOfString;
function GetNextUD:TArrayOfSingle;
//function CalKDJ4Boll():TArrayOfSingle;
constructor Create(FileName:String);

end;


implementation

constructor TDayData.Create(FileName: string);
begin
//inherited;
FFileName:=FileName;
CanDo:=False;
CanDoTest;
end;
Procedure TDayData.CanDoTest;
var
DataFile:File;
begin
try
If FileExists(FFileName) Then
Begin
AssignFile(DataFile, FFileName);
Reset(DataFile,1);
DayCount:=Round(FileSize(DataFile)/RECORD_LENGTH);
CanDo:=True;
CloseFile(DataFile);
end
except
MessageDlg('文件读写错误,请检查文件路径。', mtInformation,[mbOk], 0);
end;
end;

function TDayData.ReadData:TReadedData;
Var I:Integer;
Var DataFile:File;
var temp:LongWord;

Begin
Try
AssignFile(DataFile, FFileName);
Reset(DataFile,1);

SetLength(Result,7);
For I := Low(Result) to High(Result) do
SetLength(Result[I],DayCount);
I:=0;
//------------------------------------------
//============把数据读入相应数组中===========
while not Eof(DataFile) do
Begin
BlockRead(DataFile, temp, RECORD_FIELD_LENGTH);
Result[0][I]:=temp;//读取日期数据放入日期数组中
BlockRead(DataFile, temp, RECORD_FIELD_LENGTH);
Result[1][I]:=temp; //开盘数据
BlockRead(DataFile, temp, RECORD_FIELD_LENGTH);
Result[2][I]:=temp; //最高
BlockRead(DataFile, temp, RECORD_FIELD_LENGTH);
Result[3][I]:=temp; //最低价
BlockRead(DataFile, temp, RECORD_FIELD_LENGTH);
Result[4][I]:=temp; //收盘
BlockRead(DataFile, temp, RECORD_FIELD_LENGTH);
Result[5][I]:=temp;// 暂时未知数据
BlockRead(DataFile, temp, RECORD_FIELD_LENGTH);
Result[6][I]:=temp;//成交量
BlockRead(DataFile, temp, RECORD_FIELD_LENGTH); //读取保留字
I:=I 1;
End;
//========================================
CloseFile(DataFile);
Except
MessageDlg('文件读写错误', mtInformation,[mbOk], 0);
End;
end;

function TDayData.GetClosePrice:TArrayOfSingle;
var
i: Integer;
temp:TReadedData;
begin
temp:=ReadData;
setlength(Result,DayCount);
for i := 0 to DayCount - 1 do
Result[i]:=Trunc(temp[4][i])/100;
end;

function TDayData.CalMA(N:Integer):TArrayOfSingle;
var
i:Integer;
temp:TArrayOfSingle;
sum:Single;
begin
Result :=nil;
temp:=GetClosePrice;
if Length(temp)*N=0 then Exit;
SetLength(Result,DayCount);
sum:=0;
for i := 0 to DayCount - 1 do
begin
Sum := Sum temp[I];
if i < N then Result[i] := Sum / (i 1)
else begin
Sum := Sum - temp[i-N];
Result[i] := Sum / N;
end;
end;
end;

function TDayData.CalBoll(N:Integer;P:Single):TBollRedArray;
var
i,j:Integer;
C:TArrayOfSingle;
temp:TArrayOfSingle;
StdTemp:array of Double;
begin
Result:=nil;
temp:=CalMA(N);
C:=GetClosePrice;
SetLength(Result,DayCount);
SetLength(StdTemp,N);
for i := 0 to DayCount - 1 do
begin
Result[i].Mid:=temp[i];
if i begin
Result[i].Upper:=temp[i];
Result[i].Lower:=temp[i];
Result[i].width:=0;
Result[i].b:=0;
end
else
begin
for j := 0 to N-i do
StdTemp[j]:=temp[i 1-N j];//最近N个数存入数组
Result[i].Upper:=temp[i] P*StdDev(StdTemp);
Result[i].Lower:=temp[i]-p*StdDev(StdTemp);
Result[i].width:=(Result[i].Upper- Result[i].Lower)/Result[i].Mid;
Result[i].b:=(C[i]-Result[i].Lower)/(Result[i].Upper-Result[i].Lower);
end;
end;
end;

function TDayData.CalYiJin;
var
i:Integer;
C:TArrayOfSingle;
begin
C:=GetClosePrice;
Result:=nil;
SetLength(Result,DayCount);
for i := 0 to DayCount- 1 do
if i>5 then
begin
if C[i-5]>C[i-6] then Result[i]:='1'
else Result[i]:='0';
if C[i-4]>C[i-5] then Result[i]:=Result[i] '1'
else Result[i]:=Result[i] '0';
if C[i-3]>C[i-4] then Result[i]:=Result[i] '1'
else Result[i]:=Result[i] '0';
if C[i-2]>C[i-3] then Result[i]:=Result[i] '1'
else Result[i]:=Result[i] '0';
if C[i-1]>C[i-2] then Result[i]:=Result[i] '1'
else Result[i]:=Result[i] '0';
if C[i]>C[i-1] then Result[i]:=Result[i] '1'
else Result[i]:=Result[i] '0';
end;
end;
function TDayData.GetNextUD;
var
i:Integer;
C:TArrayOfSingle;
begin
Result:=nil;
C:=GetClosePrice;
SetLength(Result,DayCount);
for i := 0 to DayCount - 2 do
Result[i]:=(C[i 1]-C[i])/C[i]*100;
end;
end.
//


var
frmMain: TfrmMain;
CodeTable:TStringList;
implementation

uses DayDataAnys;

{$R *.dfm}

procedure TfrmMain.Button1Click(Sender: TObject);
var
i,j:Integer;
path:String;
ReadData:TReadedData;
Close:TArrayOfSingle;
MA:TArrayOfSingle;
Boll:TBollRedArray;
YiJin:TArrayOfString;
NextUD:TArrayOfSingle;
temp:TdayData;
begin
StringGrid1.RowCount:=0;
StringGrid1.ColCount:=7;
for j := 0 to CodeTable.Count-1 do
begin
path:='C:\jcb_gfzq';
path:=path '\Vipdoc\sh\lday\';
path:=path 'sh' CodeTable[j] '.day';
temp:=TDayData.Create(path);
ReadData:=temp.ReadData;
Close:=temp.GetClosePrice;
MA:=temp.CalMA(5);
Boll:=temp.CalBoll(20,2.0);
YiJin:=temp.CalYiJin;
NextUD:=temp.GetNextUD;
for i := 0 to temp.DayCount - 1 do
begin
if NextUD[i]>9.9 then
begin
StringGrid1.RowCount:=StringGrid1.RowCount 1;
StringGrid1.Cells[0,StringGrid1.RowCount]:=IntToStr(ReadData[0][i]);
StringGrid1.Cells[1,StringGrid1.RowCount]:=Format('%.3f',[MA[i]]);
StringGrid1.Cells[2,StringGrid1.RowCount]:=Format('%.4f',[Boll[i].b]);
StringGrid1.Cells[3,StringGrid1.RowCount]:=Format('%.4f',[Boll[i].width]);
StringGrid1.Cells[4,StringGrid1.RowCount]:=Format('%s',[YiJin[i]]);
StringGrid1.Cells[5,StringGrid1.RowCount]:=Format('%.2f',[NextUD[i]]);
end;
end;
temp.Free;
ReadData:=nil;
Close:=nil;
MA:=nil;
Boll:=nil;
YiJin:=nil;
NextUD:=nil;
end;
StringGrid1.Visible:=True;

[/code]
編輯記錄
pung4pung 重新編輯於 2007-11-30 22:03:01, 註解 無‧
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#2 引用回覆 回覆 發表時間:2007-11-30 22:06:26 IP:123.193.xxx.xxx 訂閱
減少設定 StringGrid1.RowCount 的次數, 
看看狀況是否有改善,
記得要多宣告一個變數 k

[code delphi]
StringGrid1.RowCount := temp.DayCount 1; //Fixed Row

k := 0;
for i := 0 to temp.DayCount - 1 do
begin
if NextUD[i]>9.9 then
begin
//// StringGrid1.RowCount:=StringGrid1.RowCount 1;
StringGrid1.Cells[0,k 1]:=IntToStr(ReadData[0][i]);
StringGrid1.Cells[1,k 1]:=Format('%.3f',[MA[i]]);
StringGrid1.Cells[2,k 1]:=Format('%.4f',[Boll[i].b]);
StringGrid1.Cells[3,k 1]:=Format('%.4f',[Boll[i].width]);
StringGrid1.Cells[4,k 1]:=Format('%s',[YiJin[i]]);
StringGrid1.Cells[5,k 1]:=Format('%.2f',[NextUD[i]]);
Inc(k);
end;
end;
StringGrid1.RowCount := k 1;
[/code]
編輯記錄
jow 重新編輯於 2007-11-30 22:07:18, 註解 無‧
jow 重新編輯於 2007-11-30 22:07:51, 註解 無‧
pung4pung
一般會員


發表:8
回覆:8
積分:3
註冊:2007-10-14

發送簡訊給我
#3 引用回覆 回覆 發表時間:2007-12-01 10:24:45 IP:58.248.xxx.xxx 訂閱
谢谢JOW先,但是状况没有什么改善。
我怀疑是不是1400次循环不断“打开文件-->读取文件-->处理数据"面导致速度低啊?
谁有好办法呢?


===================引 用 jow 文 章===================
減少設定 StringGrid1.RowCount 的次數,
看看狀況是否有改善,
記得要多宣告一個變數 k

jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#4 引用回覆 回覆 發表時間:2007-12-01 10:42:52 IP:123.193.xxx.xxx 訂閱
(1)相對於資料處理來說, 畫面的Repaint動作, 很花CPU時間
(2)讀檔動作每次讀取資料太小, 這也很不經濟

能否上傳一個資料檔 Sample 以及它的格式, 以方便程式測試...

===================引 用 pung4pung 文 章===================
谢谢JOW先,但是状况没有什么改善。
我怀疑是不是1400次循环不断“打开文件-->读取文件-->处理数据"面导致速度低啊?
谁有好办法呢?

syntax
尊榮會員


發表:26
回覆:1139
積分:1258
註冊:2002-04-23

發送簡訊給我
#5 引用回覆 回覆 發表時間:2007-12-01 11:21:29 IP:61.64.xxx.xxx 訂閱
使用 BeginUpdated(希望沒拼錯) 類的方式凍結 StringGride

會乾脆 Hide ,做完在 Show,這樣速度會差上約 100 倍左右 (以前幫 GIS寫的解讀程式就是這樣,前端用 GUI 秀出來,處理完要十分多鐘,被抱怨太慢,但是實際做時是 console 無任何訊息輸出,只要 13 秒,為了他要看,我就被嫌慢,GUI 本來就慢,Hide 一下吧)
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#6 引用回覆 回覆 發表時間:2007-12-01 15:03:38 IP:123.193.xxx.xxx 訂閱
這裡先提 一下, 個人在處理相關檔案的做法, 
[code delphi]
unit fMain;

interface

uses
Classes, Math, SysUtils, Forms, StdCtrls, Controls, Grids, ExtCtrls;

type
PStockRec = ^TStockRec;
TStockRec = packed record
case Integer of
0:(d: array[0..7] of Single);
1:(Date: Single;
OP: Single;
HP: Single;
LP: Single;
CP: Single;
UD: Single;
VOL: Single;
Reserve: Single);
end;

{ TStock }
TStock = class(TPersistent)
private
M: TMemoryStream;
function GetCount: Integer;
function GetRec(Index: Integer): PStockRec;
public
constructor Create(const FileName: string);
destructor Destroy; override;
property Count: Integer read GetCount;
property Rec[Index: Integer]: PStockRec read GetRec; default;
end;

{ TForm1 }
TForm1 = class(TForm)
StringGrid1: TStringGrid;
Panel1: TPanel;
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
procedure IterateStock(g: TStringGrid; Stock: TStock);
public
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

//------------------------------------------------------------------------------

{ TStock }

constructor TStock.Create(const FileName: string);
begin
inherited Create;
M := TMemoryStream.Create;
if FileExists(FileName) then
M.LoadFromFile(FileName);
end;

destructor TStock.Destroy;
begin
FreeAndNil(M);
inherited;
end;

function TStock.GetCount: Integer;
begin
Result := M.Size div SizeOf(TStockRec);
end;

function TStock.GetRec(Index: Integer): PStockRec;
begin
Result := nil;
if (Index > -1) and (Index < Count) then
Result := PStockRec(Integer(M.Memory) SizeOf(TStockRec)*Index);
end;

//------------------------------------------------------------------------------

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
begin
Button1.Tag := 0;
StringGrid1.ColWidths[0] := 64;
end;

procedure TForm1.IterateStock(g: TStringGrid; Stock: TStock);
const
DATA_FORMAT: string = '%s,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f';
COLHEADER: string = '日期,開盤價,最高價,最低價,收盤價,漲跌,成交量';
var
I, Count: Integer;
sDate: string;
begin
g.Rows[0].CommaText := COLHEADER;
Count := Stock.Count;
g.RowCount := Count 1;
for I := 0 to Count-1 do
with g.Rows[I 1], Stock[I]^ do
begin
sDate := FormatDateTime('YYYY-MM-DD', Date);
CommaText := Format(DATA_FORMAT,[sDate,OP,HP,LP,CP,UD,VOL]);
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
fn: string;
Stock: TStock;
begin
fn := 'D:\TEST.DAT';
if FileExists(fn) then
begin
Stock := TStock.Create(fn);
try
if Sender is TButton then
case TButton(Sender).Tag of
0: IterateStock(StringGrid1, Stock);
end;
finally
FreeAndNil(Stock);
end;
end;
end;

end.

[/code]
pung4pung
一般會員


發表:8
回覆:8
積分:3
註冊:2007-10-14

發送簡訊給我
#7 引用回覆 回覆 發表時間:2007-12-01 20:07:05 IP:58.248.xxx.xxx 訂閱
我试过不用StringGrid显示,直接将筛选出来的数据存一个数组内,速度还是很慢。
我又试过JOW的读取方法流 指针,速度也不快。

我的目的是从通达信股票软件目录下每只股票的日线数据文件(如sh600001.day、sh600002............共1000多个股票日线文件)的数据读入并计算相关的指标值,然后筛选出所有股票符合某条件(如涨幅>9% 、MA5五日均值>MA10十日均值等)时的各项指标组合。
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#8 引用回覆 回覆 發表時間:2007-12-02 14:23:35 IP:123.193.xxx.xxx 訂閱
思考一個問題,
計算一支股票的"涨幅"需要幾筆資料?
計算"五日均值"需要幾筆資料?
計算"十日均值"需要幾筆資料?

===================引 用 pung4pung 文 章===================
我试过不用StringGrid显示,直接将筛选出来的数据存一个数组内,速度还是很慢。
我又试过JOW的读取方法流 指针,速度也不快。

我的目的是从通达信股票软件目录下每只股票的日线数据文件(如sh600001.day、sh600002............共1000多个股票日线文件)的数据读入并计算相关的指标值,然后筛选出所有股票符合某条件(如涨幅>9% 、MA5五日均值>MA10十日均值等)时的各项指标组合。
pung4pung
一般會員


發表:8
回覆:8
積分:3
註冊:2007-10-14

發送簡訊給我
#9 引用回覆 回覆 發表時間:2007-12-02 23:45:56 IP:58.248.xxx.xxx 訂閱
不太明白JOWr 的意思。
一支股票的每天“涨幅”不就是前后两的收盘价计算的吗?但是基本上每天的数据都有一个“涨幅”值呀。

===================引 用 jow 文 章===================
思考一個問題,
計算一支股票的"涨幅"需要幾筆資料?
計算"五日均值"需要幾筆資料?
計算"十日均值"需要幾筆資料?

===================引 用 pung4pung 文 章===================
我试过不用StringGrid显示,直接将筛选出来的数据存一个数组内,速度还是很慢。
我又试过JOW的读取方法流 指针,速度也不快。

我的目的是从通达信股票软件目录下每只股票的日线数据文件(如sh600001.day、sh600002............共1000多个股票日线文件)的数据读入并计算相关的指标值,然后筛选出所有股票符合某条件(如涨幅>9% 、MA5五日均值>MA10十日均值等)时的各项指标组合。
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#10 引用回覆 回覆 發表時間:2007-12-03 09:37:21 IP:210.66.xxx.xxx 訂閱
(1)
在計算所有股票某一天的漲跌幅時, 只要計算兩天的資料,
五日和時日移動平均線也各只需要5和10天的資料

例如:
function CalcUDPer(Stock: TStock; Date: Single): Single;
begin
//計算Stock在Date那一天的漲跌幅.
end;

function CalcMA(Stock: TStock; Date: Single; MAC: Integer): Single;
begin
//計算Stock在Date那一天的 "MAC日"移動平均
end;

(2)已知條件的篩選
if (CalcUDPer(Stock, today) > 0.09) and (CalcMA(Stock,today,5) > CalcMA(Stock,today,10)) then
begin
//符合條件之股票
end;

以上程式碼在第一個條件(CalcUDPer(Stock, today) > 0.09)為 False時,
後面的(CalcMA(Stock,today,5) > CalcMA(Stock,today,10)) 就不會再被執行,
如此可減少計算的次數.

個人想法僅供參考...

相關做法如以下程式碼所示
(A) 新增搜尋函式 IndexOf()
(B)新增指標欄位計算功能物件(TCalculator)
[code delphi]
unit fMain;

interface
uses
Classes, Math, SysUtils, Forms, StdCtrls, Controls, Grids, ExtCtrls, Dialogs;

type
PStockRec = ^TStockRec;
TStockRec = packed record
case Integer of
0:(d: array[0..7] of Single);
1:(Date: Single;
OP: Single;
HP: Single;
LP: Single;
CP: Single;
UD: Single;
VOL: Single;
Reserve: Single);
end;

{ TStock }

TCalculator = class;//pre-declaration of TCalculator

TStock = class(TPersistent)
private
M: TMemoryStream;
FCalculator: TCalculator;
function GetCount: Integer;
function GetRec(Index: Integer): PStockRec;
function IndexOf(Date: Single; L, H: Integer): Integer; overload;
public
constructor Create(const FileName: string);
destructor Destroy; override;
function IndexOf(Date: Single; var Index: Integer): Boolean; overload;
property Calc: TCalculator read FCalculator;
property Count: Integer read GetCount;
property Rec[Index: Integer]: PStockRec read GetRec; default;
end;

{ TCalculator }
TCalculator = class(TPersistent)
private
FStock: TStock;
public
constructor Create(Stock: TStock);
function UDPer(Date: Single; Default: Single=0): Single;
function MA(Date: Single; MAC: Integer; Default: Single=0): Single;
property Stock: TStock read FStock;
end;

{ TForm1 }
TForm1 = class(TForm)
StringGrid1: TStringGrid;
Panel1: TPanel;
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
procedure IterateStock(g: TStringGrid; Stock: TStock);
public
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

//------------------------------------------------------------------------------

{ TStock }

constructor TStock.Create(const FileName: string);
begin
inherited Create;
FCalculator := TCalculator.Create(Self);
M := TMemoryStream.Create;
if FileExists(FileName) then
M.LoadFromFile(FileName);
end;

destructor TStock.Destroy;
begin
FreeAndNil(M);
FreeAndNil(FCalculator);
inherited;
end;

function TStock.IndexOf(Date: Single; var Index: Integer): Boolean;
begin
Index := IndexOf(Int(Date), 0, Count-1);
Result := Index <> -1;
end;

function TStock.IndexOf(Date: Single; L, H: Integer): Integer;
var
M: Integer;
D: Single;
begin
Result := -1;
if L <= H then
begin
M := (L H) shr 1;
D := PSingle(Rec[M])^;
if Date = D then Result := M
else if Date < D then Result := IndexOf(Date,L,M-1)
else Result := IndexOf(Date,M 1,H);
end;
end;

function TStock.GetCount: Integer;
begin
Result := M.Size div SizeOf(TStockRec);
end;

function TStock.GetRec(Index: Integer): PStockRec;
begin
Result := nil;
if (Index > -1) and (Index < Count) then
Result := PStockRec(Integer(M.Memory) SizeOf(TStockRec)*Index);
end;

//------------------------------------------------------------------------------

{ TCalculator }

constructor TCalculator.Create(Stock: TStock);
begin
inherited Create;
FStock := Stock;
end;

function TCalculator.UDPer(Date, Default: Single): Single;
var
I: Integer;
begin
Result := Default;
if Stock.IndexOf(Date, I) then
if (I > 0) and (Stock[I-1].CP > 0) then
Result := Stock[I].CP / Stock[I-1].CP - 1;
end;

function TCalculator.MA(Date: Single; MAC: Integer; Default: Single): Single;
var
I, K: Integer;
sum: Single;
begin
Result := Default;
if (MAC>0) and Stock.IndexOf(Date, I) then
begin
K := 0;
sum := 0;
repeat
sum := sum Stock[I].CP;
Dec(I);
Inc(K);
until (I<0) or (K=MAC);
Result := sum / K;
end;
end;

//------------------------------------------------------------------------------

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
begin
Button1.Tag := 0;
Button2.Tag := 1;
Button1.OnClick := Button1Click;
Button2.OnClick := Button1Click;
StringGrid1.ColWidths[0] := 64;
end;

procedure TForm1.IterateStock(g: TStringGrid; Stock: TStock);
const
DATA_FORMAT: string = '%s,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f';
COLHEADER: string = '日期,開盤價,最高價,最低價,收盤價,漲跌,成交量';
var
I, Count: Integer;
sDate: string;
begin
g.Rows[0].CommaText := COLHEADER;
Count := Stock.Count;
g.RowCount := Count 1;
for I := 0 to Count-1 do
with g.Rows[I 1], Stock[I]^ do
begin
sDate := FormatDateTime('YYYY-MM-DD', Date);
CommaText := Format(DATA_FORMAT,[sDate,OP,HP,LP,CP,UD,VOL]);
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
fn: string;
Stock: TStock;
Index: Integer;
ADate: Single;
begin
fn := 'D:\TEST.DAT';
if FileExists(fn) then
begin
Stock := TStock.Create(fn);
try
if Sender is TButton then
case TButton(Sender).Tag of
0: IterateStock(StringGrid1, Stock);//Button1
1:begin//Button2
ADate := Int(EncodeDate(2007,11,29));
if Stock.IndexOf(ADate, Index) then
begin
ShowMessage(FormatDateTime('YYYY-MM-DD', Stock.Rec[Index].Date));
ShowMessage(Format('漲跌幅=%.2f%%', [Stock.Calc.UDPer(ADate,0)*100]));
ShowMessage(Format('5MA=%.2f', [Stock.Calc.MA(ADate,5,0)]));
end;
end;
end;
finally
FreeAndNil(Stock);
end;
end;
end;
end.

[/code]
編輯記錄
jow 重新編輯於 2007-12-03 10:02:04, 註解 無‧
jow 重新編輯於 2007-12-03 10:02:40, 註解 無‧
jow 重新編輯於 2007-12-03 10:54:51, 註解 無‧
jow 重新編輯於 2007-12-03 11:05:49, 註解 無‧
jow 重新編輯於 2007-12-03 11:08:57, 註解 無‧
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#11 引用回覆 回覆 發表時間:2007-12-03 12:31:29 IP:210.66.xxx.xxx 訂閱
pung4pung
一般會員


發表:8
回覆:8
積分:3
註冊:2007-10-14

發送簡訊給我
#12 引用回覆 回覆 發表時間:2007-12-04 20:17:03 IP:58.248.xxx.xxx 訂閱
已按JOW兄的代码进行测试,如果有1000只股票,找出每天涨幅大于2%的数据,
则我将JOW兄代码改变如下进行测试,筛选数据速度也是比较慢。可能这种操作真是必须要费时吧。

[code delphi]
procedure TForm1.Button1Click(Sender: TObject);
const
DATA_FORMAT: string = '%s,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f';
COLHEADER: string = '日期,开盘¤,最高¤,最低¤,收盘¤,涨跌,成交量';
var
i,j,k: Integer;
fn: string;
Stock: TStock;
sDate:string;
begin
StringGrid1.Hide ;
fn := 'TEST.DAT';
StringGrid1.RowCount:=1;
StringGrid1.Rows[0].CommaText := COLHEADER;
k:=0;
for i := 0 to 1000 do
begin
if FileExists(fn) then
begin
Stock := TStock.Create(fn);
try
StringGrid1.RowCount:=StringGrid1.RowCount Stock.Count;
for j := 0 to Stock.Count - 1 do
if Stock.Calc.UDPer(Stock[j].Date,0) >0.02 then
with StringGrid1.Rows[k 1], Stock[j]^ do
begin
sDate := FormatDateTime('YYYY-MM-DD', Date);
CommaText := Format(DATA_FORMAT,[sDate,OP,HP,LP,CP,UD,VOL]);
Inc(k);
end;
finally
FreeAndNil(Stock);
end;
StringGrid1.RowCount:=k 1;
end;
end;
StringGrid1.Show;
end;

[/code]



===================引 用 jow 文 章===================
測試程式碼下載

http://delphi.ktop.com.tw/board.php?cid=31&fid=97&tid=91548
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#13 引用回覆 回覆 發表時間:2007-12-04 22:25:11 IP:123.193.xxx.xxx 訂閱
(1)
我的測試資料檔內有5000筆資料, 然後你執行了1001次,
所以LOOP總共跑了 5000x1001次

(2)
你的程式碼計算和顯示交叉執行, 雖然Visible設成False,
可是這樣仍然會很慢,

(3)實際運用上, 應該是計算1000支股票, 在特定一天的漲跌幅
這樣才有比較的意義吧?!!


以下寫了一個測試動作, 約略說明如下:
(1)計算1000股票, 每次5000筆資料
(2)用一個TStringList, L 來Keep計算過程產出的結果,
並排除相同結果的儲存, 如:

if not L.Find(S, K) then L.Add(S);

所以會比你之前的程式多花些時間在搜尋 與排序的動作.

(3)整個計算動作完畢後, 再進行顯示結果的動作

(4)在我電腦上執行, 所花費的時間約為 16672ms

[code delphi]
//------------------------------------------------------------------------------
procedure TForm1.Button4Click(Sender: TObject);
const
STOCK_COUNT = 1000;
DATA_FORMAT: string = '%s,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f';
COLHEADER: string = '日期,開盤價,最高價,最低價,收盤價,漲跌,成交量';
var
T: Cardinal;
I, J, K: Integer;
fn, S: string;
Stock: TStock;
L: TStringList;
begin
T := GetTickCount();
try
L := TStringList.Create;
try
L.Sorted := True;//使用L.Find(), 必須將L排序
fn := 'TEST.DAT';
for I := 0 to STOCK_COUNT-1 do
begin
if FileExists(fn) then
begin
Stock := TStock.Create(fn);
try
for J := 0 to Stock.Count-1 do
with Stock[J]^ do
if Stock.Calc.UDPer(Date) > 0.02 then
begin
S := FormatDateTime('YYYY-MM-DD', Date);
S := Format(DATA_FORMAT,[S,OP,HP,LP,CP,UD,VOL]);
if not L.Find(S, K) then L.Add(S);
end;
finally
Stock.Free;//使用FreeAndNil(Stock)會多一次function call.
end;
end;
end;
//顯示結果***********************************
if L.Count > 0 then
begin
StringGrid1.RowCount := L.Count 1;
StringGrid1.Rows[0].CommaText := COLHEADER;
for I := 0 to L.Count-1 do
StringGrid1.Rows[I 1].CommaText := L[I];
end;
//顯示結果***********************************
finally
FreeAndNil(L);
end;
finally
Label1.Caption := IntToStr(GetTickCount()-T);
end;
end;
//------------------------------------------------------------------------------
[/code]

編輯記錄
jow 重新編輯於 2007-12-04 22:26:44, 註解 無‧
jow 重新編輯於 2007-12-04 22:29:30, 註解 無‧
pung4pung
一般會員


發表:8
回覆:8
積分:3
註冊:2007-10-14

發送簡訊給我
#14 引用回覆 回覆 發表時間:2007-12-05 20:11:56 IP:58.248.xxx.xxx 訂閱
多谢JOW兄,按你的方法运算与显示分开,速度又快了8%左右。都算OK啦!

本例总结:1、运算代码与显示代码分开;
2、使用TstringList用来储存运算中数量不断增加的值 ;
3、GUI显示前可先Hide;
4、减少StringGrid的Row 不断赋值;
5、运算类分离实现;


另注:不只是取得当天的涨幅>2%的原因是:为了取得历史数据中第二天涨幅大于5%的那天的各项指标值,汇成一个表,
看看有什么规律,Logic回归看看之类的。呵呵!
系統時間:2024-04-29 15:01:04
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!