implementing DataStream
This commit is contained in:
@@ -68,7 +68,7 @@ type
|
||||
procedure PaintBoxMouseLeave(Sender: TObject);
|
||||
procedure SymbolComboBoxChange(Sender: TObject); // Event handler for symbol selection change
|
||||
private
|
||||
FDataServer: IDataServer<TAskBidItem>;
|
||||
FDataServer: IAuraDataServer<TAskBidItem>;
|
||||
FActiveOHLCCache: TOHLC;
|
||||
FCandleWidthInPixels: Integer;
|
||||
FCandleSpacing: Integer;
|
||||
@@ -87,7 +87,7 @@ type
|
||||
FSymbolFiles: TArray<string>; // Stores full paths from FindOldestFilesPerSymbol
|
||||
|
||||
procedure PopulateTimeframeComboBox;
|
||||
procedure PopulateSymbolComboBox;
|
||||
procedure SetupDataServer;
|
||||
procedure EnsureCacheForCurrentTimeframe(ARebuildIfPresent: Boolean = False);
|
||||
procedure ClearAllCachesInForm;
|
||||
procedure DrawChart(ACanvas: TCanvas; ARect: TRect);
|
||||
@@ -260,8 +260,6 @@ var
|
||||
BuilderNCaptionKey, BuilderVCaptionKey: string; // These will be the unique keys
|
||||
BuilderNDescription, BuilderVDescription: string;
|
||||
begin
|
||||
FDataServer := TAskBidServer.Create;
|
||||
|
||||
IsMemoryLow :=
|
||||
function: Boolean
|
||||
var
|
||||
@@ -280,6 +278,9 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
// Assuming we have a valid default value in the Path-Edit:
|
||||
SetupDataServer;
|
||||
|
||||
FCandleWidthInPixels := InitialCandleWidth;
|
||||
FCandleSpacing := InitialCandleSpacing;
|
||||
FDisplayStartIndex := 0;
|
||||
@@ -323,10 +324,6 @@ begin
|
||||
FMouseCurrentlyInChartArea := False;
|
||||
PaintBox.OnMouseLeave := PaintBoxMouseLeave;
|
||||
FBufferBitmap := TBitmap.Create;
|
||||
SetLength(FSymbolFiles, 0); // Initialize FSymbolFiles array
|
||||
|
||||
// Assuming we have a valid default value in the Path-Edit:
|
||||
PopulateSymbolComboBox;
|
||||
end;
|
||||
|
||||
procedure TChartForm.FormDestroy(Sender: TObject);
|
||||
@@ -597,7 +594,7 @@ begin
|
||||
begin
|
||||
DataPathEdit.Text := selectedDirectory; // Update the edit box with the selected directory
|
||||
Memo.Lines.Add(FormatDateTime('yyyy-mm-dd hh:nn:ss', Now) + ' - Data directory selected: ' + selectedDirectory);
|
||||
PopulateSymbolComboBox;
|
||||
SetupDataServer;
|
||||
end
|
||||
else
|
||||
begin
|
||||
@@ -1475,16 +1472,18 @@ begin
|
||||
Memo.Lines.Add('GoToCurrent: Already showing the latest candles.');
|
||||
end;
|
||||
|
||||
procedure TChartForm.PopulateSymbolComboBox;
|
||||
procedure TChartForm.SetupDataServer;
|
||||
var
|
||||
fileName: string;
|
||||
pathValue, symbolValue: string;
|
||||
yearValue, monthValue: Integer;
|
||||
i: Integer;
|
||||
begin
|
||||
FDataServer := TAuraTABFileServer.Create( DataPathEdit.Text );
|
||||
|
||||
var currTxt := SymbolComboBox.Text;
|
||||
|
||||
FSymbolFiles := FindOldestFilesPerSymbol(DataPathEdit.Text); // Find all relevant symbol files [cite: 238]
|
||||
FSymbolFiles := FDataServer.EnumerateAssetFiles;
|
||||
SymbolComboBox.Items.Clear;
|
||||
SymbolComboBox.ClearSelection; // Ensure no previous selection remains
|
||||
SymbolComboBox.Text := '';
|
||||
@@ -1502,8 +1501,7 @@ begin
|
||||
for i := Low(FSymbolFiles) to High(FSymbolFiles) do
|
||||
begin
|
||||
fileName := FSymbolFiles[i];
|
||||
// TryParseFileName extracts symbol from the filename. [cite: 237]
|
||||
if TryParseFileName(fileName, pathValue, symbolValue, yearValue, monthValue) then
|
||||
if TAuraTABFileServer.TryParseFileName(fileName, pathValue, symbolValue, yearValue, monthValue) then
|
||||
begin
|
||||
SymbolComboBox.Items.AddObject(
|
||||
Format('%s %.2d-%.4d', [symbolValue, monthValue, yearValue]),
|
||||
|
||||
@@ -3,15 +3,20 @@ unit Myc.ChartDataController;
|
||||
interface
|
||||
|
||||
uses
|
||||
System.SysUtils, System.Classes, System.Generics.Collections, System.StrUtils,
|
||||
System.SysUtils,
|
||||
System.Classes,
|
||||
System.Generics.Collections,
|
||||
System.StrUtils,
|
||||
Myc.Futures,
|
||||
Myc.Trade.DataPoint, Myc.Trade.DataStream, Myc.OHLCCache;
|
||||
Myc.Trade.DataPoint,
|
||||
Myc.Trade.DataStream,
|
||||
Myc.OHLCCache;
|
||||
|
||||
type
|
||||
TTimeframeSetting = record
|
||||
Caption: string; // Unique key identifier (e.g., "M1", "Auto", "Every 20 Ticks")
|
||||
Caption: string; // Unique key identifier (e.g., "M1", "Auto", "Every 20 Ticks")
|
||||
Description: string; // User-friendly description for UI
|
||||
Seconds: Int64; // TF_AUTO_AGGREGATION, TF_TICK_BY_TICK, TF_GENERIC_CALLBACK, or >0
|
||||
Seconds: Int64; // TF_AUTO_AGGREGATION, TF_TICK_BY_TICK, TF_GENERIC_CALLBACK, or >0
|
||||
end;
|
||||
|
||||
TChartDataController = class
|
||||
@@ -21,22 +26,24 @@ type
|
||||
FTimeframeSettingsArray: TArray<TTimeframeSetting>; // Now includes registered generic builders
|
||||
FMemoLog: TStrings;
|
||||
FGenericBuilders: TDictionary<string, IGenericCandleBuilder>; // Keyed by TTimeframeSetting.Caption
|
||||
FDataServer: IDataServer<TAskBidItem>;
|
||||
FDataServer: IAuraDataServer<TAskBidItem>;
|
||||
|
||||
procedure InitializeBaseTimeframeSettings; // Renamed for clarity
|
||||
function GetGenericBuilder(const ABuilderCaption: string): IGenericCandleBuilder;
|
||||
public
|
||||
constructor Create(const ADataServer: IDataServer<TAskBidItem>; AMemoTarget: TStrings);
|
||||
constructor Create(const ADataServer: IAuraDataServer<TAskBidItem>; AMemoTarget: TStrings);
|
||||
destructor Destroy; override;
|
||||
|
||||
procedure LoadTickDataSeries(const AFileName: string);
|
||||
|
||||
// GetOrBuildCache now uses a single ASelectedTimeframeCaption for all types of timeframes.
|
||||
function GetOrBuildCache( const ASelectedTimeframeCaption: string; // e.g., "M1", "Auto", "Every 20 Ticks"
|
||||
AAutoAggCandleWidth: Integer;
|
||||
AAutoAggCandleSpacing: Integer;
|
||||
AAutoAggPaintBoxClientWidth: Integer;
|
||||
AForceRebuild: Boolean): TOHLC;
|
||||
function GetOrBuildCache(
|
||||
const ASelectedTimeframeCaption: string; // e.g., "M1", "Auto", "Every 20 Ticks"
|
||||
AAutoAggCandleWidth: Integer;
|
||||
AAutoAggCandleSpacing: Integer;
|
||||
AAutoAggPaintBoxClientWidth: Integer;
|
||||
AForceRebuild: Boolean
|
||||
): TOHLC;
|
||||
|
||||
procedure ClearAllDataAndCaches;
|
||||
function GetTickDataCount: Integer;
|
||||
@@ -45,9 +52,7 @@ type
|
||||
function HasData: Boolean;
|
||||
|
||||
// ABuilderCaption is the unique key used for FTimeframeSettingsArray.Caption and FGenericBuilders key.
|
||||
procedure RegisterGenericBuilder(const ABuilderCaption: string;
|
||||
const ABuilderDescription: string;
|
||||
ABuilder: IGenericCandleBuilder);
|
||||
procedure RegisterGenericBuilder(const ABuilderCaption: string; const ABuilderDescription: string; ABuilder: IGenericCandleBuilder);
|
||||
// GetGenericBuilderCaptions is removed. Use GetAvailableTimeframes.
|
||||
function GetAvailableTimeframes: TArray<TTimeframeSetting>;
|
||||
end;
|
||||
@@ -62,12 +67,12 @@ const
|
||||
|
||||
{ TChartDataController }
|
||||
|
||||
constructor TChartDataController.Create(const ADataServer: IDataServer<TAskBidItem>; AMemoTarget: TStrings);
|
||||
constructor TChartDataController.Create(const ADataServer: IAuraDataServer<TAskBidItem>; AMemoTarget: TStrings);
|
||||
var
|
||||
I: Integer; // Standard loop variable
|
||||
begin
|
||||
inherited Create;
|
||||
FDataServer:=ADataServer;
|
||||
FDataServer := ADataServer;
|
||||
FMemoLog := AMemoTarget;
|
||||
FGenericBuilders := TDictionary<string, IGenericCandleBuilder>.Create;
|
||||
|
||||
@@ -105,20 +110,59 @@ begin
|
||||
InitialSettings := TList<TTimeframeSetting>.Create;
|
||||
try
|
||||
// Define standard, non-generic timeframes
|
||||
ts.Caption := 'Auto'; ts.Description := 'Auto (Screen Fit)'; ts.Seconds := TF_AUTO_AGGREGATION; InitialSettings.Add(ts);
|
||||
ts.Caption := 'Tick'; ts.Description := 'Tick-by-Tick'; ts.Seconds := TF_TICK_BY_TICK; InitialSettings.Add(ts);
|
||||
ts.Caption := 'Auto';
|
||||
ts.Description := 'Auto (Screen Fit)';
|
||||
ts.Seconds := TF_AUTO_AGGREGATION;
|
||||
InitialSettings.Add(ts);
|
||||
ts.Caption := 'Tick';
|
||||
ts.Description := 'Tick-by-Tick';
|
||||
ts.Seconds := TF_TICK_BY_TICK;
|
||||
InitialSettings.Add(ts);
|
||||
// The old "Generic Rule" placeholder is removed. Generic rules are added via RegisterGenericBuilder.
|
||||
ts.Caption := 'M1'; ts.Description := '1 Minute (M1)'; ts.Seconds := 60; InitialSettings.Add(ts);
|
||||
ts.Caption := 'M5'; ts.Description := '5 Minutes (M5)'; ts.Seconds := 5 * 60; InitialSettings.Add(ts);
|
||||
ts.Caption := 'M10'; ts.Description := '10 Minutes (M10)'; ts.Seconds := 10 * 60; InitialSettings.Add(ts);
|
||||
ts.Caption := 'M15'; ts.Description := '15 Minutes (M15)'; ts.Seconds := 15 * 60; InitialSettings.Add(ts);
|
||||
ts.Caption := 'M30'; ts.Description := '30 Minutes (M30)'; ts.Seconds := 30 * 60; InitialSettings.Add(ts);
|
||||
ts.Caption := 'H1'; ts.Description := '1 Hour (H1)'; ts.Seconds := 60 * 60; InitialSettings.Add(ts);
|
||||
ts.Caption := 'H4'; ts.Description := '4 Hours (H4)'; ts.Seconds := 4 * 60 * 60; InitialSettings.Add(ts);
|
||||
ts.Caption := 'D1'; ts.Description := '1 Day (D1)'; ts.Seconds := dcSecsPerDayConst; InitialSettings.Add(ts);
|
||||
ts.Caption := 'W1'; ts.Description := '1 Week (W1)'; ts.Seconds := 7 * dcSecsPerDayConst; InitialSettings.Add(ts);
|
||||
ts.Caption := 'MN1'; ts.Description := '1 Month (MN1)'; ts.Seconds := 30 * dcSecsPerDayConst; InitialSettings.Add(ts);
|
||||
ts.Caption := 'Y1'; ts.Description := '1 Year (Y1)'; ts.Seconds := 365 * dcSecsPerDayConst; InitialSettings.Add(ts);
|
||||
ts.Caption := 'M1';
|
||||
ts.Description := '1 Minute (M1)';
|
||||
ts.Seconds := 60;
|
||||
InitialSettings.Add(ts);
|
||||
ts.Caption := 'M5';
|
||||
ts.Description := '5 Minutes (M5)';
|
||||
ts.Seconds := 5 * 60;
|
||||
InitialSettings.Add(ts);
|
||||
ts.Caption := 'M10';
|
||||
ts.Description := '10 Minutes (M10)';
|
||||
ts.Seconds := 10 * 60;
|
||||
InitialSettings.Add(ts);
|
||||
ts.Caption := 'M15';
|
||||
ts.Description := '15 Minutes (M15)';
|
||||
ts.Seconds := 15 * 60;
|
||||
InitialSettings.Add(ts);
|
||||
ts.Caption := 'M30';
|
||||
ts.Description := '30 Minutes (M30)';
|
||||
ts.Seconds := 30 * 60;
|
||||
InitialSettings.Add(ts);
|
||||
ts.Caption := 'H1';
|
||||
ts.Description := '1 Hour (H1)';
|
||||
ts.Seconds := 60 * 60;
|
||||
InitialSettings.Add(ts);
|
||||
ts.Caption := 'H4';
|
||||
ts.Description := '4 Hours (H4)';
|
||||
ts.Seconds := 4 * 60 * 60;
|
||||
InitialSettings.Add(ts);
|
||||
ts.Caption := 'D1';
|
||||
ts.Description := '1 Day (D1)';
|
||||
ts.Seconds := dcSecsPerDayConst;
|
||||
InitialSettings.Add(ts);
|
||||
ts.Caption := 'W1';
|
||||
ts.Description := '1 Week (W1)';
|
||||
ts.Seconds := 7 * dcSecsPerDayConst;
|
||||
InitialSettings.Add(ts);
|
||||
ts.Caption := 'MN1';
|
||||
ts.Description := '1 Month (MN1)';
|
||||
ts.Seconds := 30 * dcSecsPerDayConst;
|
||||
InitialSettings.Add(ts);
|
||||
ts.Caption := 'Y1';
|
||||
ts.Description := '1 Year (Y1)';
|
||||
ts.Seconds := 365 * dcSecsPerDayConst;
|
||||
InitialSettings.Add(ts);
|
||||
FTimeframeSettingsArray := InitialSettings.ToArray;
|
||||
finally
|
||||
InitialSettings.Free;
|
||||
@@ -130,9 +174,11 @@ begin
|
||||
Result := Copy(FTimeframeSettingsArray); // Returns a copy of the current (potentially dynamic) list
|
||||
end;
|
||||
|
||||
procedure TChartDataController.RegisterGenericBuilder(const ABuilderCaption: string;
|
||||
const ABuilderDescription: string;
|
||||
ABuilder: IGenericCandleBuilder);
|
||||
procedure TChartDataController.RegisterGenericBuilder(
|
||||
const ABuilderCaption: string;
|
||||
const ABuilderDescription: string;
|
||||
ABuilder: IGenericCandleBuilder
|
||||
);
|
||||
var
|
||||
NewTimeframeSetting: TTimeframeSetting;
|
||||
I: Integer;
|
||||
@@ -150,7 +196,12 @@ begin
|
||||
if CompareText(FTimeframeSettingsArray[I].Caption, ABuilderCaption) = 0 then
|
||||
begin
|
||||
if FMemoLog <> nil then
|
||||
FMemoLog.Add(Format('DataController: Cannot register generic builder. A timeframe (base or generic) with caption "%s" already exists.', [ABuilderCaption]));
|
||||
FMemoLog.Add(
|
||||
Format(
|
||||
'DataController: Cannot register generic builder. A timeframe (base or generic) with caption "%s" already exists.',
|
||||
[ABuilderCaption]
|
||||
)
|
||||
);
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
@@ -173,7 +224,12 @@ begin
|
||||
// for an existing generic timeframe caption that was somehow registered differently.
|
||||
// For safety, let's log and replace if this happens.
|
||||
if FMemoLog <> nil then
|
||||
FMemoLog.Add(Format('DataController: Warning - Generic builder key "%s" already in dictionary, but not found as a TimeframeSetting caption. Replacing builder interface.', [ABuilderCaption]));
|
||||
FMemoLog.Add(
|
||||
Format(
|
||||
'DataController: Warning - Generic builder key "%s" already in dictionary, but not found as a TimeframeSetting caption. Replacing builder interface.',
|
||||
[ABuilderCaption]
|
||||
)
|
||||
);
|
||||
FGenericBuilders.Remove(ABuilderCaption);
|
||||
FGenericBuilders.Add(ABuilderCaption, ABuilder);
|
||||
end
|
||||
@@ -194,7 +250,12 @@ begin
|
||||
FOHLCCacheList.Add(nil); // Use TList.Add method
|
||||
|
||||
if FMemoLog <> nil then
|
||||
FMemoLog.Add(Format('DataController: Registered new generic builder timeframe: Caption="%s", Description="%s".', [ABuilderCaption, ABuilderDescription]));
|
||||
FMemoLog.Add(
|
||||
Format(
|
||||
'DataController: Registered new generic builder timeframe: Caption="%s", Description="%s".',
|
||||
[ABuilderCaption, ABuilderDescription]
|
||||
)
|
||||
);
|
||||
end;
|
||||
end;
|
||||
|
||||
@@ -214,8 +275,7 @@ begin
|
||||
try
|
||||
FTickDataArray := FDataServer.LoadDataSeries(AFileName).WaitFor();
|
||||
if FMemoLog <> nil then
|
||||
FMemoLog.Add(Format('DataController: Loading tick records from series: %s',
|
||||
[AFileName]));
|
||||
FMemoLog.Add(Format('DataController: Loading tick records from series: %s', [AFileName]));
|
||||
except
|
||||
on E: Exception do
|
||||
begin
|
||||
@@ -226,9 +286,11 @@ begin
|
||||
end;
|
||||
|
||||
// ASelectedTimeframeCaption is the UNIQUE key (e.g. "M1", "Auto", or "Every 20 Ticks")
|
||||
function TChartDataController.GetOrBuildCache(const ASelectedTimeframeCaption: string;
|
||||
function TChartDataController.GetOrBuildCache(
|
||||
const ASelectedTimeframeCaption: string;
|
||||
AAutoAggCandleWidth, AAutoAggCandleSpacing, AAutoAggPaintBoxClientWidth: Integer;
|
||||
AForceRebuild: Boolean): TOHLC;
|
||||
AForceRebuild: Boolean
|
||||
): TOHLC;
|
||||
var
|
||||
Index: Integer;
|
||||
CacheNeedsRebuild: Boolean;
|
||||
@@ -269,28 +331,48 @@ begin
|
||||
FOHLCCacheList[Index] := CacheAtIndex;
|
||||
CacheNeedsRebuild := True;
|
||||
if FMemoLog <> nil then
|
||||
FMemoLog.Add(Format('DataController: Cache for [%s] (Desc: "%s") is nil. Creating & Building...',
|
||||
[CurrentTimeframeSetting.Caption, CurrentTimeframeSetting.Description]));
|
||||
FMemoLog.Add(
|
||||
Format(
|
||||
'DataController: Cache for [%s] (Desc: "%s") is nil. Creating & Building...',
|
||||
[CurrentTimeframeSetting.Caption, CurrentTimeframeSetting.Description]
|
||||
)
|
||||
);
|
||||
end
|
||||
else if not CacheAtIndex.IsValid then
|
||||
begin
|
||||
CacheNeedsRebuild := True;
|
||||
if FMemoLog <> nil then
|
||||
FMemoLog.Add(Format('DataController: Cache for [%s] (Desc: "%s") exists but is invalid. Rebuilding...',
|
||||
[CurrentTimeframeSetting.Caption, CurrentTimeframeSetting.Description]));
|
||||
FMemoLog.Add(
|
||||
Format(
|
||||
'DataController: Cache for [%s] (Desc: "%s") exists but is invalid. Rebuilding...',
|
||||
[CurrentTimeframeSetting.Caption, CurrentTimeframeSetting.Description]
|
||||
)
|
||||
);
|
||||
end
|
||||
else if CacheAtIndex.AggregationTimeframeSeconds <> CurrentTimeframeSetting.Seconds then
|
||||
begin
|
||||
if FMemoLog <> nil then
|
||||
FMemoLog.Add(Format('DataController: Aggregation timeframe (seconds) mismatch for [%s] (Desc: "%s"). Cache has %ds, requested %ds. Forcing rebuild.',
|
||||
[CurrentTimeframeSetting.Caption, CurrentTimeframeSetting.Description, CacheAtIndex.AggregationTimeframeSeconds, CurrentTimeframeSetting.Seconds]));
|
||||
FMemoLog.Add(
|
||||
Format(
|
||||
'DataController: Aggregation timeframe (seconds) mismatch for [%s] (Desc: "%s"). Cache has %ds, requested %ds. Forcing rebuild.',
|
||||
[
|
||||
CurrentTimeframeSetting.Caption,
|
||||
CurrentTimeframeSetting.Description,
|
||||
CacheAtIndex.AggregationTimeframeSeconds,
|
||||
CurrentTimeframeSetting.Seconds
|
||||
]
|
||||
)
|
||||
);
|
||||
CacheNeedsRebuild := True;
|
||||
end;
|
||||
|
||||
// If it's a generic callback timeframe, an additional check for builder matching might be needed if not forced.
|
||||
// The TOHLC's ApproxTimePerCandleText stores "(BuilderCaption)" for generic builds.
|
||||
// ASelectedTimeframeCaption *is* the builder caption for generic rules.
|
||||
if (CurrentTimeframeSetting.Seconds = TF_GENERIC_CALLBACK) and (not CacheNeedsRebuild) and Assigned(CacheAtIndex) and CacheAtIndex.IsValid then
|
||||
if (CurrentTimeframeSetting.Seconds = TF_GENERIC_CALLBACK)
|
||||
and (not CacheNeedsRebuild)
|
||||
and Assigned(CacheAtIndex)
|
||||
and CacheAtIndex.IsValid then
|
||||
begin
|
||||
// For generic, CurrentTimeframeSetting.Caption is the Builder's caption.
|
||||
// We check if the existing cache was built with this same builder.
|
||||
@@ -301,8 +383,17 @@ begin
|
||||
if CacheAtIndex.ApproxTimePerCandleText <> ExpectedCacheBuilderInfo then
|
||||
begin
|
||||
if FMemoLog <> nil then
|
||||
FMemoLog.Add(Format('DataController: Generic builder changed for timeframe key [%s] (Desc: "%s"). Cache has info "%s", current builder key implies info "%s". Forcing rebuild.',
|
||||
[CurrentTimeframeSetting.Caption, CurrentTimeframeSetting.Description, CacheAtIndex.ApproxTimePerCandleText, ExpectedCacheBuilderInfo]));
|
||||
FMemoLog.Add(
|
||||
Format(
|
||||
'DataController: Generic builder changed for timeframe key [%s] (Desc: "%s"). Cache has info "%s", current builder key implies info "%s". Forcing rebuild.',
|
||||
[
|
||||
CurrentTimeframeSetting.Caption,
|
||||
CurrentTimeframeSetting.Description,
|
||||
CacheAtIndex.ApproxTimePerCandleText,
|
||||
ExpectedCacheBuilderInfo
|
||||
]
|
||||
)
|
||||
);
|
||||
CacheNeedsRebuild := True;
|
||||
end;
|
||||
end;
|
||||
@@ -312,8 +403,12 @@ begin
|
||||
if HasData then
|
||||
begin
|
||||
if FMemoLog <> nil then
|
||||
FMemoLog.Add(Format('DataController: Building cache for [%s] (Desc: "%s")...',
|
||||
[CurrentTimeframeSetting.Caption, CurrentTimeframeSetting.Description]));
|
||||
FMemoLog.Add(
|
||||
Format(
|
||||
'DataController: Building cache for [%s] (Desc: "%s")...',
|
||||
[CurrentTimeframeSetting.Caption, CurrentTimeframeSetting.Description]
|
||||
)
|
||||
);
|
||||
|
||||
if CurrentTimeframeSetting.Seconds = TF_GENERIC_CALLBACK then
|
||||
begin
|
||||
@@ -322,8 +417,12 @@ begin
|
||||
if not Assigned(LGenericBuilder) then
|
||||
begin
|
||||
if FMemoLog <> nil then
|
||||
FMemoLog.Add(Format('DataController: Cannot build cache for generic timeframe [%s] (Desc: "%s"). Builder with this caption not found in dictionary.',
|
||||
[CurrentTimeframeSetting.Caption, CurrentTimeframeSetting.Description]));
|
||||
FMemoLog.Add(
|
||||
Format(
|
||||
'DataController: Cannot build cache for generic timeframe [%s] (Desc: "%s"). Builder with this caption not found in dictionary.',
|
||||
[CurrentTimeframeSetting.Caption, CurrentTimeframeSetting.Description]
|
||||
)
|
||||
);
|
||||
CacheAtIndex.ClearCache();
|
||||
Result := CacheAtIndex;
|
||||
Exit;
|
||||
@@ -350,8 +449,12 @@ begin
|
||||
else
|
||||
begin
|
||||
if FMemoLog <> nil then
|
||||
FMemoLog.Add(Format('DataController: Using existing valid cache for [%s] (Desc: "%s")',
|
||||
[CurrentTimeframeSetting.Caption, CurrentTimeframeSetting.Description]));
|
||||
FMemoLog.Add(
|
||||
Format(
|
||||
'DataController: Using existing valid cache for [%s] (Desc: "%s")',
|
||||
[CurrentTimeframeSetting.Caption, CurrentTimeframeSetting.Description]
|
||||
)
|
||||
);
|
||||
end;
|
||||
Result := CacheAtIndex;
|
||||
end;
|
||||
@@ -394,7 +497,9 @@ begin
|
||||
// The current behavior is that builder registrations and the full list of timeframe definitions persist.
|
||||
|
||||
if FMemoLog <> nil then // This is the line (approx. 376) the user reported
|
||||
FMemoLog.Add('DataController: Instance data and OHLC caches cleared. Registered builders and timeframe definitions (including custom ones) remain.');
|
||||
FMemoLog.Add(
|
||||
'DataController: Instance data and OHLC caches cleared. Registered builders and timeframe definitions (including custom ones) remain.'
|
||||
);
|
||||
end;
|
||||
|
||||
function TChartDataController.GetTickDataCount: Integer;
|
||||
@@ -414,7 +519,9 @@ begin
|
||||
else
|
||||
begin
|
||||
if FMemoLog <> nil then
|
||||
FMemoLog.Add(Format('DataController: Attempted to access invalid tick data index %d. Count is %d.', [AIndex, Length(FTickDataArray)]));
|
||||
FMemoLog.Add(
|
||||
Format('DataController: Attempted to access invalid tick data index %d. Count is %d.', [AIndex, Length(FTickDataArray)])
|
||||
);
|
||||
Result := Default(TDataRecord<TAskBidItem>);
|
||||
end;
|
||||
end;
|
||||
|
||||
Reference in New Issue
Block a user