Files
MycLib/Src/Myc.Trade.DataServer.pas
T
2025-06-07 10:12:41 +02:00

156 lines
4.5 KiB
ObjectPascal

unit Myc.Trade.DataServer;
interface
uses
System.SysUtils,
System.Generics.Collections,
Myc.Lazy,
Myc.Trade.DataPoint,
Myc.Trade.DataSeries,
Myc.Signals, // Added for TLatch
Myc.Futures; // Added for TFuture
type
IDataServer<T> = interface
['{A6E246A2-E84E-49AB-A63E-333E561E488C}']
function GetIsLiveData: TMutable<Boolean>;
function GetChunk(var Data: array of T): Integer;
property IsLiveData: TMutable<Boolean> read GetIsLiveData;
end;
TDataServer<T> = class(TInterfacedObject, IDataServer<T>)
protected
function GetIsLiveData: TMutable<Boolean>; virtual; abstract;
function GetChunk(var Data: array of T): Integer; virtual; abstract;
end;
IDataServerNode<T> = interface
['{DA3531F1-158E-4A63-8E5A-34089C537B1B}']
function CreateDataServer: IDataServer<T>;
end;
TDataServerNode<T> = class(TInterfacedObject, IDataServerNode<T>)
public
// Factory method to create the actual data server instance.
function CreateDataServer: IDataServer<T>; virtual; abstract;
end;
TTABFileServer = class(TDataServer<TDataPoint<TAskBidItem>>)
private
FFilename: String;
FIsLiveData: TMutable<Boolean>.IWriteable;
// Internal state
FCurrentFileName: string;
FCurrentData: TFuture<TArray<TAskBid.TTick>>;
FNextFileName: string;
FNextData: TFuture<TArray<TAskBid.TTick>>;
FCurrPosInFile: Int64;
FCurrentIdx: Int64;
FLastTimeStamp: TDateTime;
protected
function GetChunk(var Data: array of TDataPoint<TAskBidItem>): Integer; override;
function GetIsLiveData: TMutable<Boolean>; override;
public
constructor Create(const AFilename: String);
procedure AfterConstruction; override;
end;
implementation
uses
System.IOUtils;
{ TTABFileServer<T> }
constructor TTABFileServer.Create(const AFilename: String);
begin
inherited Create;
FFilename := AFilename;
FNextData := TFuture<TArray<TAskBid.TTick>>.Null;
FIsLiveData := TMutable<Boolean>.CreateWriteable(false);
end;
procedure TTABFileServer.AfterConstruction;
begin
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;
function TTABFileServer.GetChunk(var Data: array of TDataPoint<TAskBidItem>): Integer;
begin
Result := 0;
if FCurrentData.Done.IsSet then
begin
var maxLen := Length(Data);
var currData := FCurrentData.Value;
while Result < MaxLen do
begin
if FCurrPosInFile >= Length(currData) then
begin
// Next File!
FCurrentData := FNextData;
FCurrentFileName := FNextFileName;
FCurrPosInFile := 0;
FNextFileName := '';
FNextData := TFuture<TArray<TAskBid.TTick>>.Null;
if FCurrentFileName <> '' then
begin
FNextFileName := FindNextDataFile(FCurrentFileName);
if FNextFileName <> '' then
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;
break;
end;
var item := currData[FCurrPosInFile];
if FLastTimeStamp < item.TimeStamp then
begin
FLastTimeStamp := item.TimeStamp;
Data[Result].Create(FCurrentIdx, FLastTimeStamp, item.Data);
inc(Result);
inc(FCurrentIdx);
end;
inc(FCurrPosInFile);
end;
end;
end;
function TTABFileServer.GetIsLiveData: TMutable<Boolean>;
begin
Result := FIsLiveData;
end;
end.