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 = interface ['{A6E246A2-E84E-49AB-A63E-333E561E488C}'] function GetIsLiveData: TMutable; function GetChunk(var Data: array of T): Integer; property IsLiveData: TMutable read GetIsLiveData; end; TDataServer = class(TInterfacedObject, IDataServer) protected function GetIsLiveData: TMutable; virtual; abstract; function GetChunk(var Data: array of T): Integer; virtual; abstract; end; IDataServerNode = interface ['{DA3531F1-158E-4A63-8E5A-34089C537B1B}'] function CreateDataServer: IDataServer; end; TDataServerNode = class(TInterfacedObject, IDataServerNode) public // Factory method to create the actual data server instance. function CreateDataServer: IDataServer; virtual; abstract; end; TTABFileServer = class(TDataServer>) private FFilename: String; FIsLiveData: TMutable.IWriteable; // Internal state FCurrentFileName: string; FCurrentData: TFuture>; FNextFileName: string; FNextData: TFuture>; FCurrPosInFile: Int64; FCurrentIdx: Int64; FLastTimeStamp: TDateTime; protected function GetChunk(var Data: array of TDataPoint): Integer; override; function GetIsLiveData: TMutable; override; public constructor Create(const AFilename: String); procedure AfterConstruction; override; end; implementation uses System.IOUtils; { TTABFileServer } constructor TTABFileServer.Create(const AFilename: String); begin inherited Create; FFilename := AFilename; FNextData := TFuture>.Null; FIsLiveData := TMutable.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): 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>.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; begin Result := FIsLiveData; end; end.