148 lines
4.1 KiB
ObjectPascal
148 lines
4.1 KiB
ObjectPascal
unit TestMethodCallFromRecordParams;
|
|
|
|
interface
|
|
|
|
uses
|
|
System.SysUtils,
|
|
System.Classes,
|
|
System.Rtti,
|
|
Myc.Data.Records,
|
|
Myc.Data.Pipeline,
|
|
Myc.Trade.Indicators;
|
|
|
|
type
|
|
TMyWorker = class
|
|
public
|
|
type
|
|
TParams = record
|
|
Log: Int64;
|
|
text: String;
|
|
end;
|
|
|
|
TArgs = record
|
|
xyz: Double;
|
|
end;
|
|
|
|
TResult = record
|
|
val: Int64;
|
|
desc: String;
|
|
end;
|
|
|
|
[IndicatorFactory]
|
|
class function CreateFactory: TIndicatorFactoryProc<TParams, TArgs, TResult>; static;
|
|
end;
|
|
|
|
// SMA indicator for demonstration purposes
|
|
TSmaIndicator = class
|
|
public
|
|
type
|
|
TParams = record
|
|
Period: Integer;
|
|
end;
|
|
|
|
TArgs = record
|
|
Value: Double;
|
|
end;
|
|
|
|
TResult = record
|
|
Sma: Double;
|
|
end;
|
|
|
|
[IndicatorFactory]
|
|
class function CreateFactory: TIndicatorFactoryProc<TParams, TArgs, TResult>; static;
|
|
end;
|
|
|
|
procedure Test1(const Log: TStrings);
|
|
implementation
|
|
|
|
uses
|
|
System.Math;
|
|
|
|
class function TMyWorker.CreateFactory: TIndicatorFactoryProc<TParams, TArgs, TResult>;
|
|
begin
|
|
Result :=
|
|
function(const Params: TParams): TConvertFunc<TArgs, TResult>
|
|
begin
|
|
var Log := TStrings(Params.Log);
|
|
var text := Params.text;
|
|
|
|
Result :=
|
|
function(const Args: TArgs): TResult
|
|
begin
|
|
// Use Format to avoid locale issues with float conversion
|
|
Log.Add(Format('Val=%f (...%s)', [Args.xyz, text]));
|
|
Result.desc := 'done';
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure Test1(const Log: TStrings);
|
|
begin
|
|
var fact := TGenericIndicatorFactory.CreateFromTemplate<TMyWorker>;
|
|
|
|
var params: TMyWorker.TParams;
|
|
params.Log := Int64(Log);
|
|
params.text := 'The quick brown fox jumps...';
|
|
|
|
var indi := fact.CreateIndicator<TMyWorker.TParams, TMyWorker.TArgs, TMyWorker.TResult>(params);
|
|
|
|
var args: TMyWorker.TArgs;
|
|
args.xyz := 3.14159;
|
|
|
|
var res := indi(args);
|
|
|
|
Log.Add('Final result description: ' + res.desc);
|
|
end;
|
|
|
|
{ TSmaIndicator }
|
|
|
|
class function TSmaIndicator.CreateFactory: TIndicatorFactoryProc<TParams, TArgs, TResult>;
|
|
begin
|
|
Result :=
|
|
function(const Params: TParams): TConvertFunc<TArgs, TResult>
|
|
var
|
|
// State for the indicator closure
|
|
period: Integer;
|
|
buffer: TArray<Double>;
|
|
sum: Double;
|
|
count: Integer;
|
|
idx: Integer;
|
|
begin
|
|
period := Params.Period;
|
|
if period <= 0 then
|
|
raise Exception.Create('Period must be positive');
|
|
|
|
SetLength(buffer, period);
|
|
sum := 0.0;
|
|
count := 0;
|
|
idx := 0;
|
|
|
|
Result :=
|
|
function(const Args: TArgs): TResult
|
|
begin
|
|
// If the buffer is full, subtract the oldest value that is about to be overwritten.
|
|
if count >= period then
|
|
sum := sum - buffer[idx];
|
|
|
|
// Add the new value to the buffer and the sum.
|
|
buffer[idx] := Args.Value;
|
|
sum := sum + Args.Value;
|
|
|
|
// Advance the index for the circular buffer.
|
|
idx := (idx + 1) mod period;
|
|
|
|
// Increment the fill count until the buffer is full for the first time.
|
|
if count < period then
|
|
inc(count);
|
|
|
|
// Calculate the SMA. The result is the average of the values currently in the buffer.
|
|
if count > 0 then
|
|
Result.Sma := sum / count
|
|
else
|
|
Result.Sma := 0.0;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
end.
|