Testing TValue as Params

This commit is contained in:
Michael Schimmel
2025-07-28 00:55:39 +02:00
parent 1ddc295c9d
commit 75675b8dc1
4 changed files with 107 additions and 145 deletions
+37 -43
View File
@@ -6,6 +6,7 @@ uses
System.SysUtils,
System.Math,
System.Rtti,
Myc.Data.Records,
Myc.Data.Pipeline,
Myc.Data.Series,
Myc.Trade.Types,
@@ -147,9 +148,7 @@ type
DPeriod: Integer;
end;
TArgs = record
High: Double;
Low: Double;
Close: Double;
Value: TOhlcItem;
end;
TResult = record
K: Double; // %K line
@@ -157,12 +156,12 @@ type
end;
[IndicatorFactory]
class function CreateFactory: TIndicatorFactoryProc<TParams, TArgs, TResult>; static;
class function CreateStochastic(KPeriod, DPeriod: Integer): TConvertFunc<TArgs, TResult>; overload; static;
class function CreateStochastic(KPeriod, DPeriod: Integer): TConvertFunc<TOhlcItem, TResult>; overload; static;
// Creates a Stochastic Oscillator using an injectable moving average for the %D line.
class function CreateStochastic(
KPeriod: Integer;
const SmaD: TConvertFunc<Double, Double>
): TConvertFunc<TArgs, TStochastic.TResult>; overload; static;
): TConvertFunc<TOhlcItem, TStochastic.TResult>; overload; static;
end;
[IndicatorName('StdDev', 'Standard Deviation')]
@@ -215,17 +214,15 @@ type
Period: Integer;
end;
TArgs = record
High: Double;
Low: Double;
Close: Double;
Value: TOhlcItem;
end;
TResult = record
ATR: Double;
end;
[IndicatorFactory]
class function CreateFactory: TIndicatorFactoryProc<TParams, TArgs, TResult>; static;
class function CreateATR(Period: Integer): TConvertFunc<TArgs, Double>; overload; static;
class function CreateATR(const MovAvgTR: TConvertFunc<Double, Double>): TConvertFunc<TArgs, Double>; overload; static;
class function CreateATR(Period: Integer): TConvertFunc<TOhlcItem, Double>; overload; static;
class function CreateATR(const MovAvgTR: TConvertFunc<Double, Double>): TConvertFunc<TOhlcItem, Double>; overload; static;
end;
[IndicatorName('KC', 'Keltner Channels')]
@@ -238,9 +235,7 @@ type
Multiplier: Double;
end;
TArgs = record
High: Double;
Low: Double;
Close: Double;
Value: TOhlcItem;
end;
TResult = record
UpperBand: Double;
@@ -249,12 +244,12 @@ type
end;
[IndicatorFactory]
class function CreateFactory: TIndicatorFactoryProc<TParams, TArgs, TResult>; static;
class function CreateKeltnerChannels(Period: Integer; Multiplier: Double): TConvertFunc<TArgs, TResult>; overload; static;
class function CreateKeltnerChannels(Period: Integer; Multiplier: Double): TConvertFunc<TOhlcItem, TResult>; overload; static;
class function CreateKeltnerChannels(
const MovAvgMiddle: TConvertFunc<Double, Double>;
const AtrFunc: TConvertFunc<TATR.TArgs, Double>;
const AtrFunc: TConvertFunc<TOhlcItem, Double>;
Multiplier: Double
): TConvertFunc<TArgs, TKeltnerChannels.TResult>; overload; static;
): TConvertFunc<TOhlcItem, TKeltnerChannels.TResult>; overload; static;
end;
[IndicatorName('Mean', 'Mean Value')]
@@ -713,22 +708,25 @@ begin
Result :=
function(const Params: TParams): TConvertFunc<TArgs, TResult>
var
stochFunc: TConvertFunc<TArgs, TResult>;
stochFunc: TConvertFunc<TOhlcItem, TResult>;
begin
stochFunc := CreateStochastic(Params.KPeriod, Params.DPeriod);
Result := function(const Value: TArgs): TResult begin Result := stochFunc(Value); end;
Result := function(const Value: TArgs): TResult begin Result := stochFunc(Value.Value); end;
end;
end;
class function TStochastic.CreateStochastic(KPeriod, DPeriod: Integer): TConvertFunc<TArgs, TResult>;
class function TStochastic.CreateStochastic(KPeriod, DPeriod: Integer): TConvertFunc<TOhlcItem, TStochastic.TResult>;
begin
Result := CreateStochastic(KPeriod, TSMA.CreateSMA(DPeriod));
end;
// Creates a Stochastic Oscillator using an injectable moving average for the %D line.
class function TStochastic.CreateStochastic(KPeriod: Integer; const SmaD: TConvertFunc<Double, Double>): TConvertFunc<TArgs, TResult>;
class function TStochastic.CreateStochastic(
KPeriod: Integer;
const SmaD: TConvertFunc<Double, Double>
): TConvertFunc<TOhlcItem, TStochastic.TResult>;
var
buffer: TArray<TArgs>;
buffer: TArray<TOhlcItem>;
highDeque: TLightDeque;
lowDeque: TLightDeque;
valueCount: Int64;
@@ -736,7 +734,7 @@ begin
if (KPeriod <= 0) then
begin
Result :=
function(const Value: TArgs): TResult
function(const Value: TOhlcItem): TResult
begin
Result.K := Double.NaN;
Result.D := Double.NaN;
@@ -750,7 +748,7 @@ begin
valueCount := 0;
Result :=
function(const Value: TArgs): TStochastic.TResult
function(const Value: TOhlcItem): TStochastic.TResult
var
currentIndex, firstIndex, lastIndex: Integer;
highestHigh, lowestLow: Double;
@@ -928,25 +926,25 @@ begin
Result :=
function(const Params: TParams): TConvertFunc<TArgs, TResult>
var
atrFunc: TConvertFunc<TArgs, Double>;
atrFunc: TConvertFunc<TOhlcItem, Double>;
begin
atrFunc := CreateATR(Params.Period);
Result := function(const Value: TArgs): TResult begin Result.ATR := atrFunc(Value); end;
Result := function(const Value: TArgs): TResult begin Result.ATR := atrFunc(Value.Value); end;
end;
end;
class function TATR.CreateATR(Period: Integer): TConvertFunc<TArgs, Double>;
class function TATR.CreateATR(Period: Integer): TConvertFunc<TOhlcItem, Double>;
begin
Result := CreateATR(TEMA.CreateEMA(Period));
end;
// Calculates the Average True Range (ATR) using an injectable moving average.
class function TATR.CreateATR(const MovAvgTR: TConvertFunc<Double, Double>): TConvertFunc<TArgs, Double>;
class function TATR.CreateATR(const MovAvgTR: TConvertFunc<Double, Double>): TConvertFunc<TOhlcItem, Double>;
begin
var sourceData: TSeries<TArgs>;
var sourceData: TSeries<TOhlcItem>;
Result :=
function(const Value: TArgs): Double
function(const Value: TOhlcItem): Double
var
tr: Double;
begin
@@ -970,19 +968,20 @@ end;
{ TKeltnerChannels }
class function TKeltnerChannels.CreateFactory: TIndicatorFactoryProc<TParams, TArgs, TResult>;
class function TKeltnerChannels.CreateFactory:
TIndicatorFactoryProc<TKeltnerChannels.TParams, TKeltnerChannels.TArgs, TKeltnerChannels.TResult>;
begin
Result :=
function(const Params: TParams): TConvertFunc<TArgs, TResult>
var
kcFunc: TConvertFunc<TArgs, TResult>;
kcFunc: TConvertFunc<TOhlcItem, TResult>;
begin
kcFunc := CreateKeltnerChannels(Params.Period, Params.Multiplier);
Result := function(const Value: TArgs): TResult begin Result := kcFunc(Value); end;
Result := function(const Value: TArgs): TResult begin Result := kcFunc(Value.Value); end;
end;
end;
class function TKeltnerChannels.CreateKeltnerChannels(Period: Integer; Multiplier: Double): TConvertFunc<TArgs, TResult>;
class function TKeltnerChannels.CreateKeltnerChannels(Period: Integer; Multiplier: Double): TConvertFunc<TOhlcItem, TResult>;
begin
Result := CreateKeltnerChannels(TEMA.CreateEMA(Period), TATR.CreateATR(Period), Multiplier);
end;
@@ -990,12 +989,12 @@ end;
// Calculates Keltner Channels using an injectable ATR and middle band moving average.
class function TKeltnerChannels.CreateKeltnerChannels(
const MovAvgMiddle: TConvertFunc<Double, Double>;
const AtrFunc: TConvertFunc<TATR.TArgs, Double>;
const AtrFunc: TConvertFunc<TOhlcItem, Double>;
Multiplier: Double
): TConvertFunc<TArgs, TKeltnerChannels.TResult>;
): TConvertFunc<TOhlcItem, TKeltnerChannels.TResult>;
begin
Result :=
function(const Value: TArgs): TKeltnerChannels.TResult
function(const Value: TOhlcItem): TKeltnerChannels.TResult
var
atrValue, middleValue, typicalPrice: Double;
begin
@@ -1004,12 +1003,7 @@ begin
// Get values from the provided indicator functions.
middleValue := MovAvgMiddle(typicalPrice);
var atrArgs: TATR.TArgs;
atrArgs.High := Value.High;
atrArgs.Low := Value.Low;
atrArgs.Close := Value.Close;
atrValue := AtrFunc(atrArgs);
atrValue := AtrFunc(Value);
// Set default NaN values for the warm-up period.
Result.MiddleBand := middleValue;