Streamlining DataServer
This commit is contained in:
@@ -12,24 +12,17 @@ uses
|
||||
Myc.Futures; // Added for TFuture
|
||||
|
||||
type
|
||||
IDataProvider = interface
|
||||
['{B2A9996C-724B-4416-A882-595B7E58066D}']
|
||||
procedure Fetch;
|
||||
end;
|
||||
|
||||
IDataServer<T> = interface(IDataProvider)
|
||||
IDataServer<T> = interface
|
||||
['{A6E246A2-E84E-49AB-A63E-333E561E488C}']
|
||||
function GetData: TMutable<TArray<T>>;
|
||||
function GetIsLiveData: TMutable<Boolean>;
|
||||
property Data: TMutable<TArray<T>> read GetData;
|
||||
function GetChunk(var Data: array of T): Integer;
|
||||
property IsLiveData: TMutable<Boolean> read GetIsLiveData;
|
||||
end;
|
||||
|
||||
TDataServer<T> = class(TInterfacedObject, IDataServer<T>, IDataProvider)
|
||||
TDataServer<T> = class(TInterfacedObject, IDataServer<T>)
|
||||
protected
|
||||
function GetData: TMutable<TArray<T>>; virtual; abstract;
|
||||
function GetIsLiveData: TMutable<Boolean>; virtual; abstract;
|
||||
procedure Fetch; virtual; abstract;
|
||||
function GetChunk(var Data: array of T): Integer; virtual; abstract;
|
||||
end;
|
||||
|
||||
IDataServerNode<T> = interface
|
||||
@@ -43,13 +36,10 @@ type
|
||||
function CreateDataServer: IDataServer<T>; virtual; abstract;
|
||||
end;
|
||||
|
||||
TTABFileServer = class(TDataServer<ITickData>)
|
||||
TTABFileServer = class(TDataServer<TDataPoint<TAskBidItem>>)
|
||||
|
||||
private
|
||||
FFilename: String;
|
||||
// The maximum number of data points to be produced per Fetch call.
|
||||
FMaxFetch: Integer;
|
||||
FHasNewData: TEvent;
|
||||
FNeedNewChunk: Boolean;
|
||||
FIsLiveData: TMutable<Boolean>.IWriteable;
|
||||
|
||||
// Internal state
|
||||
@@ -57,21 +47,16 @@ type
|
||||
FCurrentData: TFuture<TArray<TAskBid.TTick>>;
|
||||
FNextFileName: string;
|
||||
FNextData: TFuture<TArray<TAskBid.TTick>>;
|
||||
FData: TMutable<TArray<ITickData>>;
|
||||
FCurrPosInFile: Int64;
|
||||
FCurrChunk: TArray<ITickData>;
|
||||
FLoadGate: TLatch;
|
||||
FCurrentIdx: Int64;
|
||||
FLastTimeStamp: TDateTime;
|
||||
|
||||
function ConvertTicks(var Idx: Int64; const Ticks: TArray<TAskBid.TTick>): TArray<ITickData>;
|
||||
function UpdateChunk: TArray<ITickData>;
|
||||
protected
|
||||
procedure Fetch; override;
|
||||
function GetData: TMutable<TArray<ITickData>>; override;
|
||||
function GetChunk(var Data: array of TDataPoint<TAskBidItem>): Integer; override;
|
||||
function GetIsLiveData: TMutable<Boolean>; override;
|
||||
public
|
||||
constructor Create(const AFilename: String; AMaxFetch: Integer);
|
||||
constructor Create(const AFilename: String);
|
||||
procedure AfterConstruction; override;
|
||||
end;
|
||||
|
||||
implementation
|
||||
@@ -81,78 +66,45 @@ uses
|
||||
|
||||
{ TTABFileServer<T> }
|
||||
|
||||
constructor TTABFileServer.Create(const AFilename: String; AMaxFetch: Integer);
|
||||
constructor TTABFileServer.Create(const AFilename: String);
|
||||
begin
|
||||
inherited Create;
|
||||
FFilename := AFilename;
|
||||
FMaxFetch := AMaxFetch;
|
||||
|
||||
FNextData := TFuture<TArray<TAskBid.TTick>>.Null;
|
||||
FNeedNewChunk := true;
|
||||
FIsLiveData := TMutable<Boolean>.CreateWriteable(false);
|
||||
|
||||
FHasNewData := TEvent.CreateEvent;
|
||||
FData := TMutable<TArray<ITickData>>.Construct(FHasNewData.Signal, function: TArray<ITickData> begin Result := UpdateChunk; end);
|
||||
end;
|
||||
|
||||
function TTABFileServer.ConvertTicks(var Idx: Int64; const Ticks: TArray<TAskBid.TTick>): TArray<ITickData>;
|
||||
procedure TTABFileServer.AfterConstruction;
|
||||
begin
|
||||
SetLength(Result, Length(Ticks));
|
||||
for var i := 0 to High(Ticks) do
|
||||
begin
|
||||
Result[i] := TDataPoint<ITick>.Create(Idx, Ticks[i].OADateTime, 1, TTick.Create(Ticks[i].Data.Ask, Ticks[i].Data.Bid));
|
||||
inc(Idx);
|
||||
end;
|
||||
inherited;
|
||||
|
||||
FCurrentFileName := FFilename;
|
||||
FCurrentData := TAskBid.LoadDataFile(FCurrentFileName);
|
||||
FCurrPosInFile := 0;
|
||||
FCurrentIdx := 0;
|
||||
FIsLiveData.SetValue(false);
|
||||
FLastTimeStamp := 0;
|
||||
FFilename := '';
|
||||
|
||||
FNextFileName := FindNextDataFile(FCurrentFileName);
|
||||
if FNextFileName <> '' then
|
||||
FNextData := TAskBid.LoadDataFile(FNextFileName);
|
||||
exit;
|
||||
end;
|
||||
|
||||
procedure TTABFileServer.Fetch;
|
||||
function TTABFileServer.GetChunk(var Data: array of TDataPoint<TAskBidItem>): Integer;
|
||||
begin
|
||||
|
||||
// Check if the source filename has changed.
|
||||
if (FFilename <> FCurrentFileName) and (FFilename <> '') then
|
||||
begin
|
||||
// Filename has changed, initialize by loading the new file.
|
||||
FCurrentFileName := FFilename;
|
||||
FCurrentData := TAskBid.LoadDataFile(TLatch.Enqueue(FLoadGate), FCurrentFileName);
|
||||
FCurrPosInFile := 0;
|
||||
FCurrentIdx := 0;
|
||||
FIsLiveData.SetValue(false);
|
||||
FLastTimeStamp := 0;
|
||||
FFilename := '';
|
||||
|
||||
FNextFileName := FindNextDataFile(FCurrentFileName);
|
||||
if FNextFileName <> '' then
|
||||
FNextData := TAskBid.LoadDataFile(TLatch.Enqueue(FLoadGate), FNextFileName);
|
||||
end;
|
||||
|
||||
FHasNewData.Notify;
|
||||
FNeedNewChunk := true;
|
||||
FCurrChunk := nil;
|
||||
end;
|
||||
|
||||
function TTABFileServer.GetData: TMutable<TArray<ITickData>>;
|
||||
begin
|
||||
Result := FData;
|
||||
end;
|
||||
|
||||
function TTABFileServer.GetIsLiveData: TMutable<Boolean>;
|
||||
begin
|
||||
Result := FIsLiveData;
|
||||
end;
|
||||
|
||||
function TTABFileServer.UpdateChunk: TArray<ITickData>;
|
||||
begin
|
||||
if not FNeedNewChunk then
|
||||
exit(FCurrChunk);
|
||||
FNeedNewChunk := false;
|
||||
Result := 0;
|
||||
|
||||
if FCurrentData.Done.IsSet then
|
||||
begin
|
||||
SetLength(FCurrChunk, FMaxFetch);
|
||||
var n := 0;
|
||||
while n < FMaxFetch do
|
||||
var maxLen := Length(Data);
|
||||
|
||||
var currData := FCurrentData.Value;
|
||||
while Result < MaxLen do
|
||||
begin
|
||||
if FCurrPosInFile >= Length(FCurrentData.Value) then
|
||||
if FCurrPosInFile >= Length(currData) then
|
||||
begin
|
||||
// Next File!
|
||||
FCurrentData := FNextData;
|
||||
@@ -166,31 +118,38 @@ begin
|
||||
begin
|
||||
FNextFileName := FindNextDataFile(FCurrentFileName);
|
||||
if FNextFileName <> '' then
|
||||
FNextData := TAskBid.LoadDataFile(TLatch.Enqueue(FLoadGate), FNextFileName);
|
||||
FNextData := TAskBid.LoadDataFile(FNextFileName);
|
||||
|
||||
if FCurrentData.Done.IsSet then
|
||||
begin
|
||||
currData := FCurrentData.Value;
|
||||
continue;
|
||||
end;
|
||||
end
|
||||
else
|
||||
begin
|
||||
// We're done with this series
|
||||
FIsLiveData.SetValue(true);
|
||||
end;
|
||||
|
||||
SetLength(FCurrChunk, n);
|
||||
break;
|
||||
end;
|
||||
|
||||
var currData := FCurrentData.Value[FCurrPosInFile];
|
||||
if FLastTimeStamp < currData.OADateTime then
|
||||
var item := currData[FCurrPosInFile];
|
||||
if FLastTimeStamp < item.TimeStamp then
|
||||
begin
|
||||
FLastTimeStamp := currData.OADateTime;
|
||||
FCurrChunk[n] :=
|
||||
TDataPoint<ITick>.Create(FCurrentIdx, FLastTimeStamp, 1, TTick.Create(currData.Data.Ask, currData.Data.Bid));
|
||||
FLastTimeStamp := item.TimeStamp;
|
||||
Data[Result].Create(FCurrentIdx, FLastTimeStamp, item.Data);
|
||||
inc(Result);
|
||||
inc(FCurrentIdx);
|
||||
inc(n);
|
||||
end;
|
||||
inc(FCurrPosInFile);
|
||||
end;
|
||||
end;
|
||||
Result := FCurrChunk;
|
||||
end;
|
||||
|
||||
function TTABFileServer.GetIsLiveData: TMutable<Boolean>;
|
||||
begin
|
||||
Result := FIsLiveData;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
Reference in New Issue
Block a user