DataServer
Bugfix in DataSeries
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user