From 021ff61774146e38840071d3c4f04049e373647f Mon Sep 17 00:00:00 2001 From: Michael Schimmel Date: Fri, 11 Jul 2025 12:00:36 +0200 Subject: [PATCH] Processor-Result --- AuraTrader/FirstStrategy.pas | 34 ++++++++++++++++++---------------- AuraTrader/MainForm.pas | 3 ++- AuraTrader/Myc.Fmx.Chart.pas | 18 ++++++++++++++---- Src/Myc.Trade.DataPoint.pas | 25 +++++++++++++++---------- Src/Myc.Trade.DataStream.pas | 4 +++- 5 files changed, 52 insertions(+), 32 deletions(-) diff --git a/AuraTrader/FirstStrategy.pas b/AuraTrader/FirstStrategy.pas index d7d87a5..72093e5 100644 --- a/AuraTrader/FirstStrategy.pas +++ b/AuraTrader/FirstStrategy.pas @@ -41,13 +41,12 @@ type property Observers: IMycBroadcast read GetObservers; end; - TMycConverter = class abstract(TInterfacedObject, IMycProcessor, IMycConverter) + TMycConverter = class abstract(TMycProcessor, IMycConverter) private FObservers: TMycBroadcast; protected procedure Broadcast(const Value: T); function GetObservers: IMycBroadcast; - procedure ProcessData(const Value: S); virtual; abstract; public constructor Create; destructor Destroy; override; @@ -59,7 +58,7 @@ type private FFunc: TConvertFunc; protected - procedure ProcessData(const Value: S); override; + function ProcessData(const Value: S): Boolean; override; public constructor Create(const AFunc: TConvertFunc); end; @@ -79,7 +78,7 @@ type TMycIndicator = class abstract(TMycConverter, TArray>, IMycIndicator) protected function GetLookback: Integer; virtual; abstract; - procedure ProcessData(const Value: TArray); override; abstract; + function ProcessData(const Value: TArray): Boolean; override; abstract; public property Lookback: Integer read GetLookback; end; @@ -92,7 +91,7 @@ type FFunc: TConvertFunc; protected function GetLookback: Integer; override; - procedure ProcessData(const Value: TArray); override; + function ProcessData(const Value: TArray): Boolean; override; public constructor Create(ALookback: Integer; const AFunc: TConvertFunc); end; @@ -120,7 +119,7 @@ type constructor Create(const ATimeframe: TTimeframe; const AStateText: TWriteable); // Process new data. This is called concurrently and must not have side effects out of the scope of this class! - procedure ProcessData(const Values: TArray>); override; + function ProcessData(const Values: TArray>): Boolean; override; property CurrentBar: TDataPoint read GetCurrentBar; property StateText: TWriteable read GetStateText; @@ -140,7 +139,7 @@ type // Calculates the Weighted Moving Average for the most recent data. function CalculateWMA(const Series: TMycDataArray; const Period: Integer): Double; protected - procedure ProcessData(const Values: TArray); override; + function ProcessData(const Values: TArray): Boolean; override; function GetLookback: Integer; override; public constructor Create(const APeriod: Integer); @@ -175,8 +174,7 @@ begin FLinkedStrategies.Notify( function(const Processor: IMycProcessor): Boolean begin - Processor.ProcessData(cValue); - Result := true; + Result := Processor.ProcessData(cValue); end ); finally @@ -242,7 +240,7 @@ begin Result := FTimeframe; end; -procedure TTicksToTimeframe.ProcessData(const Values: TArray>); +function TTicksToTimeframe.ProcessData(const Values: TArray>): Boolean; var point: TDataPoint; midPrice: Single; @@ -251,6 +249,7 @@ var currentBar: TOhlcItem; producedBars: TList>; begin + Result := true; producedBars := TList>.Create; try // Process each incoming data point @@ -343,7 +342,7 @@ begin Result := FPeriod + FPeriodSqrt - 1; end; -procedure THullMovingAverage.ProcessData(const Values: TArray); +function THullMovingAverage.ProcessData(const Values: TArray): Boolean; var i: Integer; price: Double; @@ -351,6 +350,8 @@ var hma: Double; resultArray: TArray; begin + Result := true; + // Pre-allocate the result array since its size is known in advance. SetLength(resultArray, Length(Values)); @@ -358,8 +359,8 @@ begin begin price := Values[i]; - // Default HMA to 0.0 for the warm-up period. - hma := 0.0; + // Default HMA to NaN for the warm-up period. + hma := Double.NaN; // Add new price to the source data array, respecting the lookback period. FSourceData := FSourceData.Add(price, FPeriod); @@ -402,8 +403,9 @@ begin FFunc := AFunc; end; -procedure TMycGenericConverter.ProcessData(const Value: S); +function TMycGenericConverter.ProcessData(const Value: S): Boolean; begin + Result := true; Broadcast(FFunc(Value)); end; @@ -419,11 +421,11 @@ begin Result := FLookback; end; -procedure TMycGenericIndicator.ProcessData(const Value: TArray); +function TMycGenericIndicator.ProcessData(const Value: TArray): Boolean; var Arr: TArray; begin - inherited; + Result := true; SetLength(Arr, Length(Value)); for var i := 0 to High(Arr) do Arr[i] := FFunc(Value[i]); diff --git a/AuraTrader/MainForm.pas b/AuraTrader/MainForm.pas index 355133f..6197fc7 100644 --- a/AuraTrader/MainForm.pas +++ b/AuraTrader/MainForm.pas @@ -450,8 +450,9 @@ begin Symbol, terminated, TMycGenericProcessor>>.Create( - procedure(const Values: TArray>) + function(const Values: TArray>): Boolean begin + Result := true; Prices := Prices.Add(Values); currLog.Value := Prices.TotalCount.ToString; diff --git a/AuraTrader/Myc.Fmx.Chart.pas b/AuraTrader/Myc.Fmx.Chart.pas index 9ce2252..90f687d 100644 --- a/AuraTrader/Myc.Fmx.Chart.pas +++ b/AuraTrader/Myc.Fmx.Chart.pas @@ -78,7 +78,7 @@ type FDataSeries: TMycDataArray; FChanged: Boolean; FLock: TSpinLock; - procedure ProcessData(const Values: TArray); + function ProcessData(const Values: TArray): Boolean; private FData: TMycDataArray; protected @@ -271,8 +271,9 @@ begin Result := FData.Count; end; -procedure TChartSeriesProcessor.ProcessData(const Values: TArray); +function TChartSeriesProcessor.ProcessData(const Values: TArray): Boolean; begin + Result := true; FLock.Enter; try FDataSeries := FDataSeries.Add(Values, 0, Length(Values), Owner.Lookback); @@ -407,8 +408,17 @@ begin if displayCount < 2 then Exit; - points.MoveTo( TPointF.Create(AXForm(0), AYForm(Data[0])) ); - for var i := 1 to displayCount - 1 do + // Skip warmup data + var n := 0; + while IsNaN(Data[n]) do + begin + inc( n ); + if n >= displaycount-2 then + exit; + end; + + points.MoveTo( TPointF.Create(AXForm(n), AYForm(Data[n])) ); + for var i := n to displayCount - 1 do points.LineTo( TPointF.Create(AXForm(i), AYForm(Data[i])) ); ACanvas.Stroke.Color := FLineColor; diff --git a/Src/Myc.Trade.DataPoint.pas b/Src/Myc.Trade.DataPoint.pas index 6aea09a..7feb315 100644 --- a/Src/Myc.Trade.DataPoint.pas +++ b/Src/Myc.Trade.DataPoint.pas @@ -30,25 +30,30 @@ type end; IMycProcessor = interface - procedure ProcessData(const Value: T); + function ProcessData(const Value: T): Boolean; end; - TMycGenericProcessor = class(TInterfacedObject, IMycProcessor) + TMycProcessor = class abstract(TInterfacedObject, IMycProcessor) + protected + function ProcessData(const Value: T): Boolean; virtual; abstract; + end; + + TMycGenericProcessor = class(TMycProcessor) type - TProc = reference to procedure(const Value: T); + TProc = reference to function(const Value: T): Boolean; private FProc: TProc; - procedure ProcessData(const Value: T); + function ProcessData(const Value: T): Boolean; override; public constructor Create(const AProc: TProc); end; TMycContainedProcessor = class(TContainedObject, IMycProcessor) type - TProc = procedure(const Value: T) of object; + TProc = function(const Value: T): Boolean of object; private FProc: TProc; - procedure ProcessData(const Value: T); + function ProcessData(const Value: T): Boolean; public constructor Create(const Controller: IInterface; const AProc: TProc); end; @@ -420,9 +425,9 @@ begin FProc := AProc; end; -procedure TMycGenericProcessor.ProcessData(const Value: T); +function TMycGenericProcessor.ProcessData(const Value: T): Boolean; begin - FProc(Value); + Result := FProc(Value); end; constructor TMycContainedProcessor.Create(const Controller: IInterface; const AProc: TProc); @@ -431,9 +436,9 @@ begin FProc := AProc; end; -procedure TMycContainedProcessor.ProcessData(const Value: T); +function TMycContainedProcessor.ProcessData(const Value: T): Boolean; begin - FProc(Value); + Result := FProc(Value); end; end. diff --git a/Src/Myc.Trade.DataStream.pas b/Src/Myc.Trade.DataStream.pas index 4187778..9308afe 100644 --- a/Src/Myc.Trade.DataStream.pas +++ b/Src/Myc.Trade.DataStream.pas @@ -436,7 +436,9 @@ begin DataFile.Chain( function(const Data: TArray>): TState begin - Processor.ProcessData(Data); + if not Processor.ProcessData(Data) then + exit( TState.Null ); + Result := ProcessFile(nextFileInfo, nextFile, cTerminated, Processor); end );