Streamlining DataServer

This commit is contained in:
Michael Schimmel
2025-06-07 10:12:41 +02:00
parent 031b99acc8
commit 2cdae3d3f6
5 changed files with 148 additions and 320 deletions
+49 -90
View File
@@ -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.