DataServer

Bugfix in DataSeries
This commit is contained in:
Michael Schimmel
2025-06-06 23:24:08 +02:00
parent a6c0c3d6b3
commit 031b99acc8
11 changed files with 369 additions and 86 deletions
+53 -57
View File
@@ -54,7 +54,7 @@ type
type
// Represents a single data point with a timestamp and generic data.
TDataPoint = packed record
OADateTime: Double;
OADateTime: TDateTime;
Data: T;
end;
@@ -77,7 +77,7 @@ type
class function ReadUncompressedData(const InputStream: TStream): TArray<TDataPoint>; static;
public
// Asynchronously loads a single data file with caching support.
class function LoadDataFile(var LoadGate: TLatch; const FileName: string): TFuture<TArray<TDataPoint>>; static;
class function LoadDataFile(const LoadGate: TState; const FileName: string): TFuture<TArray<TDataPoint>>; static;
// Asynchronously loads a complete chronological series of data files.
class function LoadDataSeries(const FileName: string): TFuture<TArray<TDataPoint>>; static;
end;
@@ -274,44 +274,44 @@ begin
end;
function FindNextDataFile(const FileName: string): string;
var
pathValue, symbolValue: string;
yearValue, monthValue: Integer;
nextBaseName, compressedPath, uncompressedPath: string;
begin
// Parse the input filename to extract its components.
if not TryParseFileName(FileName, pathValue, symbolValue, yearValue, monthValue) then
begin
exit(''); // If parsing fails, there is no 'next' file.
end;
// Calculate the next month and year.
Inc(monthValue);
if monthValue > 12 then
begin
monthValue := 1;
Inc(yearValue);
end;
// Construct the base name for the next file.
nextBaseName := Format('%s_%.4d_%.2d.tab', [symbolValue, yearValue, monthValue]);
// Check for the existence of the next file, preferring the compressed version.
compressedPath := TPath.Combine(pathValue, nextBaseName + '_zip');
if TFile.Exists(compressedPath) then
begin
exit(compressedPath);
end;
uncompressedPath := TPath.Combine(pathValue, nextBaseName);
if TFile.Exists(uncompressedPath) then
begin
exit(uncompressedPath);
end;
// If no next file is found, return an empty string.
Result := '';
end;
var
pathValue, symbolValue: string;
yearValue, monthValue: Integer;
nextBaseName, compressedPath, uncompressedPath: string;
begin
// Parse the input filename to extract its components.
if not TryParseFileName(FileName, pathValue, symbolValue, yearValue, monthValue) then
begin
exit(''); // If parsing fails, there is no 'next' file.
end;
// Calculate the next month and year.
Inc(monthValue);
if monthValue > 12 then
begin
monthValue := 1;
Inc(yearValue);
end;
// Construct the base name for the next file.
nextBaseName := Format('%s_%.4d_%.2d.tab', [symbolValue, yearValue, monthValue]);
// Check for the existence of the next file, preferring the compressed version.
compressedPath := TPath.Combine(pathValue, nextBaseName + '_zip');
if TFile.Exists(compressedPath) then
begin
exit(compressedPath);
end;
uncompressedPath := TPath.Combine(pathValue, nextBaseName);
if TFile.Exists(uncompressedPath) then
begin
exit(uncompressedPath);
end;
// If no next file is found, return an empty string.
Result := '';
end;
class destructor TDataSeries<T>.CreateClass;
begin
@@ -325,7 +325,7 @@ end;
// Asynchronously reads tick data from a single specified file.
// Returns a TFuture that will provide an array of TAskBidSeries.
class function TDataSeries<T>.LoadDataFile(var LoadGate: TLatch; const FileName: string): TFuture<TArray<TDataPoint>>;
class function TDataSeries<T>.LoadDataFile(const LoadGate: TState; const FileName: string): TFuture<TArray<TDataPoint>>;
var
parsedPath, parsedSymbol: string;
parsedYear, parsedMonth: Integer;
@@ -379,7 +379,7 @@ begin
Result :=
TFuture<TBytes>
.Construct(
TLatch.Enqueue(LoadGate),
LoadGate,
function: TBytes
begin
Result := TFile.ReadAllBytes(capFileName); // Read all bytes of the .zip file
@@ -401,7 +401,7 @@ begin
var capFileName := FileName;
Result :=
TFuture<TArray<TDataPoint>>.Construct(
TLatch.Enqueue(LoadGate),
LoadGate,
function: TArray<TDataPoint>
begin
if TFile.Exists(capFileName) then
@@ -447,6 +447,7 @@ var
liveFilePath: string;
pathName, symbolName: string;
yearValue, monthValue: Integer;
LoadGate: TLatch;
begin
// 1. Discover all sequential .tab/.tab_zip files using the new helper function.
tabFiles := TList<string>.Create;
@@ -482,12 +483,10 @@ begin
var loadedFileList := TList<TFuture<TArray<TDataPoint>>>.Create;
var loadStates := TList<TState>.Create;
try
var LoadGate: TLatch;
// Create load tasks for the historical .tab files.
for currentFile in tabFiles do
begin
var data := LoadDataFile(LoadGate, currentFile);
var data := LoadDataFile(TLatch.Enqueue(LoadGate), currentFile);
loadedFileList.Add(data);
loadStates.Add(data.Done);
end;
@@ -496,7 +495,7 @@ begin
liveData := TFuture<TArray<TDataPoint>>.Null;
if liveFilePath <> '' then
begin
liveData := LoadDataFile(LoadGate, liveFilePath);
liveData := LoadDataFile(TLatch.Enqueue(LoadGate), liveFilePath);
loadedFileList.Add(liveData);
loadStates.Add(liveData.Done);
end;
@@ -520,7 +519,7 @@ begin
var tickList := TList<TDataPoint>.Create;
try
var totalTicks := Length(liveData.Value);
var overallLastTabTickTime := 0.0;
var overallLastTabTickTime: TDateTime := 0;
for var P in loadedFiles do
Inc(totalTicks, Length(P.Value));
@@ -529,15 +528,12 @@ begin
for var P in loadedFiles do
begin
if Length(P.Value) > 0 then
begin
for var iterTickData in P.Value do
if iterTickData.OADateTime > overallLastTabTickTime then
begin
tickList.Add(iterTickData);
overallLastTabTickTime := iterTickData.OADateTime;
end;
end;
for var iterTickData in P.Value do
if overallLastTabTickTime < iterTickData.OADateTime then
begin
tickList.Add(iterTickData);
overallLastTabTickTime := iterTickData.OADateTime;
end;
end;
Result := tickList.ToArray;
finally