Generic indicator factory
This commit is contained in:
+26
-2
@@ -318,7 +318,19 @@ begin
|
|||||||
var Lowest: Double := Double.MaxValue;
|
var Lowest: Double := Double.MaxValue;
|
||||||
var Highest: Double := Double.MinValue;
|
var Highest: Double := Double.MinValue;
|
||||||
|
|
||||||
var ATR := Ohlc.Chain<Double>(TATR.CreateATR(50)).MakeParallel;
|
var ATR :=
|
||||||
|
Ohlc
|
||||||
|
.Chain<TATR.TArgs>(
|
||||||
|
TConverter<TOhlcItem, TATR.TArgs>.CreateConverter(
|
||||||
|
function(const Ohlc: TOhlcItem): TATR.TArgs
|
||||||
|
begin
|
||||||
|
Result.Close := Ohlc.Close;
|
||||||
|
Result.High := Ohlc.High;
|
||||||
|
Result.Low := Ohlc.Low;
|
||||||
|
end
|
||||||
|
))
|
||||||
|
.Chain<Double>(TATR.CreateATR(50))
|
||||||
|
.MakeParallel;
|
||||||
|
|
||||||
// next stage
|
// next stage
|
||||||
|
|
||||||
@@ -622,7 +634,19 @@ begin
|
|||||||
var Boli := Closes.MakeParallel.Chain<TBollingerBands.TResult>(TBollingerBands.CreateBollingerBands(20, 2.0));
|
var Boli := Closes.MakeParallel.Chain<TBollingerBands.TResult>(TBollingerBands.CreateBollingerBands(20, 2.0));
|
||||||
var Rsi := Closes.Chain<Double>(TRSI.CreateRSI(14));
|
var Rsi := Closes.Chain<Double>(TRSI.CreateRSI(14));
|
||||||
var Macd := Closes.MakeParallel.Chain<TMacd.TResult>(TMACD.CreateMACD(12, 26, 9));
|
var Macd := Closes.MakeParallel.Chain<TMacd.TResult>(TMACD.CreateMACD(12, 26, 9));
|
||||||
var Stoch := Ohlc.Chain<TStochastic.TResult>(TStochastic.CreateStochastic(14, 3));
|
|
||||||
|
var Stoch :=
|
||||||
|
Ohlc
|
||||||
|
.Chain<TStochastic.TArgs>(
|
||||||
|
TConverter<TOhlcItem, TStochastic.TArgs>.CreateConverter(
|
||||||
|
function(const Ohlc: TOhlcItem): TStochastic.TArgs
|
||||||
|
begin
|
||||||
|
Result.Close := Ohlc.Close;
|
||||||
|
Result.High := Ohlc.High;
|
||||||
|
Result.Low := Ohlc.Low;
|
||||||
|
end
|
||||||
|
))
|
||||||
|
.Chain<TStochastic.TResult>(TStochastic.CreateStochastic(14, 3));
|
||||||
|
|
||||||
chart.SetXAxisSeries(timeframe, Timestamps);
|
chart.SetXAxisSeries(timeframe, Timestamps);
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,19 @@ begin
|
|||||||
|
|
||||||
var Hull := Closes.Chain<Double>(THMA.CreateHMA(250)).MakeParallel;
|
var Hull := Closes.Chain<Double>(THMA.CreateHMA(250)).MakeParallel;
|
||||||
var Sma := Closes.Chain<Double>(TSMA.CreateSMA(200)).MakeParallel;
|
var Sma := Closes.Chain<Double>(TSMA.CreateSMA(200)).MakeParallel;
|
||||||
var ATR := Ohlc.Chain<Double>(TATR.CreateATR(50)).MakeParallel;
|
|
||||||
|
var ATR :=
|
||||||
|
Ohlc
|
||||||
|
.Chain<TATR.TArgs>(
|
||||||
|
TConverter<TOhlcItem, TATR.TArgs>.CreateConverter(
|
||||||
|
function(const Ohlc: TOhlcItem): TATR.TArgs
|
||||||
|
begin
|
||||||
|
Result.Close := Ohlc.Close;
|
||||||
|
Result.High := Ohlc.High;
|
||||||
|
Result.Low := Ohlc.Low;
|
||||||
|
end
|
||||||
|
))
|
||||||
|
.Chain<Double>(TATR.CreateATR(50));
|
||||||
|
|
||||||
var conv := TConverter.Join<Double>([Ohlc.Field<Double>('Low'), Ohlc.Field<Double>('High'), Closes, ATR, Hull, Sma]);
|
var conv := TConverter.Join<Double>([Ohlc.Field<Double>('Low'), Ohlc.Field<Double>('High'), Closes, ATR, Hull, Sma]);
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ type
|
|||||||
|
|
||||||
procedure Copy(Src, Dst: Pointer);
|
procedure Copy(Src, Dst: Pointer);
|
||||||
|
|
||||||
function GetSize: Integer; inline;
|
|
||||||
function GetAlignedSize: Integer; inline;
|
function GetAlignedSize: Integer; inline;
|
||||||
|
|
||||||
public
|
public
|
||||||
@@ -44,7 +43,7 @@ type
|
|||||||
|
|
||||||
property FieldType: TFieldType read FFieldType;
|
property FieldType: TFieldType read FFieldType;
|
||||||
property Name: string read FName;
|
property Name: string read FName;
|
||||||
property Size: Integer read GetSize;
|
property Size: Integer read FSize;
|
||||||
property AlignedSize: Integer read GetAlignedSize;
|
property AlignedSize: Integer read GetAlignedSize;
|
||||||
property TypeInfo: PTypeInfo read FTypeInfo;
|
property TypeInfo: PTypeInfo read FTypeInfo;
|
||||||
end;
|
end;
|
||||||
@@ -286,17 +285,9 @@ begin
|
|||||||
Copy(@Src, @Buffer[FOffset]);
|
Copy(@Src, @Buffer[FOffset]);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TDataRecord.TField.GetSize: Integer;
|
|
||||||
const
|
|
||||||
DataSize: array[TDataRecord.TFieldType] of Integer =
|
|
||||||
(sizeof(Double), sizeof(Int64), sizeof(String), sizeof(TDateTime), sizeof(TDataRecord));
|
|
||||||
begin
|
|
||||||
Result := DataSize[FFieldType];
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TDataRecord.TField.GetAlignedSize: Integer;
|
function TDataRecord.TField.GetAlignedSize: Integer;
|
||||||
begin
|
begin
|
||||||
Result := (GetSize + (Align - 1)) and not (Align - 1);
|
Result := (FSize + (Align - 1)) and not (Align - 1);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TDataRecord.TField.ToType(const [ref] Buffer: TBytes; var Dst);
|
procedure TDataRecord.TField.ToType(const [ref] Buffer: TBytes; var Dst);
|
||||||
|
|||||||
@@ -148,7 +148,9 @@ type
|
|||||||
DPeriod: Integer;
|
DPeriod: Integer;
|
||||||
end;
|
end;
|
||||||
TArgs = record
|
TArgs = record
|
||||||
Value: TOhlcItem;
|
High: Double;
|
||||||
|
Low: Double;
|
||||||
|
Close: Double;
|
||||||
end;
|
end;
|
||||||
TResult = record
|
TResult = record
|
||||||
K: Double; // %K line
|
K: Double; // %K line
|
||||||
@@ -156,12 +158,12 @@ type
|
|||||||
end;
|
end;
|
||||||
[IndicatorFactory]
|
[IndicatorFactory]
|
||||||
class function CreateFactory: TIndicatorFactoryProc<TParams, TArgs, TResult>; static;
|
class function CreateFactory: TIndicatorFactoryProc<TParams, TArgs, TResult>; 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, DPeriod: Integer): TConvertFunc<TArgs, TResult>; overload; static;
|
||||||
class function CreateStochastic(
|
class function CreateStochastic(
|
||||||
KPeriod: Integer;
|
KPeriod: Integer;
|
||||||
const SmaD: TConvertFunc<Double, Double>
|
const SmaD: TConvertFunc<Double, Double>
|
||||||
): TConvertFunc<TOhlcItem, TStochastic.TResult>; overload; static;
|
): TConvertFunc<TArgs, TStochastic.TResult>; overload; static;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
[IndicatorName('StdDev', 'Standard Deviation')]
|
[IndicatorName('StdDev', 'Standard Deviation')]
|
||||||
@@ -214,15 +216,17 @@ type
|
|||||||
Period: Integer;
|
Period: Integer;
|
||||||
end;
|
end;
|
||||||
TArgs = record
|
TArgs = record
|
||||||
Value: TOhlcItem;
|
High: Double;
|
||||||
|
Low: Double;
|
||||||
|
Close: Double;
|
||||||
end;
|
end;
|
||||||
TResult = record
|
TResult = record
|
||||||
ATR: Double;
|
ATR: Double;
|
||||||
end;
|
end;
|
||||||
[IndicatorFactory]
|
[IndicatorFactory]
|
||||||
class function CreateFactory: TIndicatorFactoryProc<TParams, TArgs, TResult>; static;
|
class function CreateFactory: TIndicatorFactoryProc<TParams, TArgs, TResult>; static;
|
||||||
class function CreateATR(Period: Integer): TConvertFunc<TOhlcItem, Double>; overload; static;
|
class function CreateATR(Period: Integer): TConvertFunc<TArgs, Double>; overload; static;
|
||||||
class function CreateATR(const MovAvgTR: TConvertFunc<Double, Double>): TConvertFunc<TOhlcItem, Double>; overload; static;
|
class function CreateATR(const MovAvgTR: TConvertFunc<Double, Double>): TConvertFunc<TArgs, Double>; overload; static;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
[IndicatorName('KC', 'Keltner Channels')]
|
[IndicatorName('KC', 'Keltner Channels')]
|
||||||
@@ -235,7 +239,9 @@ type
|
|||||||
Multiplier: Double;
|
Multiplier: Double;
|
||||||
end;
|
end;
|
||||||
TArgs = record
|
TArgs = record
|
||||||
Value: TOhlcItem;
|
High: Double;
|
||||||
|
Low: Double;
|
||||||
|
Close: Double;
|
||||||
end;
|
end;
|
||||||
TResult = record
|
TResult = record
|
||||||
UpperBand: Double;
|
UpperBand: Double;
|
||||||
@@ -244,12 +250,12 @@ type
|
|||||||
end;
|
end;
|
||||||
[IndicatorFactory]
|
[IndicatorFactory]
|
||||||
class function CreateFactory: TIndicatorFactoryProc<TParams, TArgs, TResult>; static;
|
class function CreateFactory: TIndicatorFactoryProc<TParams, TArgs, TResult>; static;
|
||||||
class function CreateKeltnerChannels(Period: Integer; Multiplier: Double): TConvertFunc<TOhlcItem, TResult>; overload; static;
|
class function CreateKeltnerChannels(Period: Integer; Multiplier: Double): TConvertFunc<TArgs, TResult>; overload; static;
|
||||||
class function CreateKeltnerChannels(
|
class function CreateKeltnerChannels(
|
||||||
const MovAvgMiddle: TConvertFunc<Double, Double>;
|
const MovAvgMiddle: TConvertFunc<Double, Double>;
|
||||||
const AtrFunc: TConvertFunc<TOhlcItem, Double>;
|
const AtrFunc: TConvertFunc<TATR.TArgs, Double>;
|
||||||
Multiplier: Double
|
Multiplier: Double
|
||||||
): TConvertFunc<TOhlcItem, TKeltnerChannels.TResult>; overload; static;
|
): TConvertFunc<TArgs, TKeltnerChannels.TResult>; overload; static;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
[IndicatorName('Mean', 'Mean Value')]
|
[IndicatorName('Mean', 'Mean Value')]
|
||||||
@@ -708,25 +714,22 @@ begin
|
|||||||
Result :=
|
Result :=
|
||||||
function(const Params: TParams): TConvertFunc<TArgs, TResult>
|
function(const Params: TParams): TConvertFunc<TArgs, TResult>
|
||||||
var
|
var
|
||||||
stochFunc: TConvertFunc<TOhlcItem, TResult>;
|
stochFunc: TConvertFunc<TArgs, TResult>;
|
||||||
begin
|
begin
|
||||||
stochFunc := CreateStochastic(Params.KPeriod, Params.DPeriod);
|
stochFunc := CreateStochastic(Params.KPeriod, Params.DPeriod);
|
||||||
Result := function(const Value: TArgs): TResult begin Result := stochFunc(Value.Value); end;
|
Result := function(const Value: TArgs): TResult begin Result := stochFunc(Value); end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class function TStochastic.CreateStochastic(KPeriod, DPeriod: Integer): TConvertFunc<TOhlcItem, TStochastic.TResult>;
|
class function TStochastic.CreateStochastic(KPeriod, DPeriod: Integer): TConvertFunc<TArgs, TResult>;
|
||||||
begin
|
begin
|
||||||
Result := CreateStochastic(KPeriod, TSMA.CreateSMA(DPeriod));
|
Result := CreateStochastic(KPeriod, TSMA.CreateSMA(DPeriod));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Creates a Stochastic Oscillator using an injectable moving average for the %D line.
|
// Creates a Stochastic Oscillator using an injectable moving average for the %D line.
|
||||||
class function TStochastic.CreateStochastic(
|
class function TStochastic.CreateStochastic(KPeriod: Integer; const SmaD: TConvertFunc<Double, Double>): TConvertFunc<TArgs, TResult>;
|
||||||
KPeriod: Integer;
|
|
||||||
const SmaD: TConvertFunc<Double, Double>
|
|
||||||
): TConvertFunc<TOhlcItem, TStochastic.TResult>;
|
|
||||||
var
|
var
|
||||||
buffer: TArray<TOhlcItem>;
|
buffer: TArray<TArgs>;
|
||||||
highDeque: TLightDeque;
|
highDeque: TLightDeque;
|
||||||
lowDeque: TLightDeque;
|
lowDeque: TLightDeque;
|
||||||
valueCount: Int64;
|
valueCount: Int64;
|
||||||
@@ -734,7 +737,7 @@ begin
|
|||||||
if (KPeriod <= 0) then
|
if (KPeriod <= 0) then
|
||||||
begin
|
begin
|
||||||
Result :=
|
Result :=
|
||||||
function(const Value: TOhlcItem): TResult
|
function(const Value: TArgs): TResult
|
||||||
begin
|
begin
|
||||||
Result.K := Double.NaN;
|
Result.K := Double.NaN;
|
||||||
Result.D := Double.NaN;
|
Result.D := Double.NaN;
|
||||||
@@ -748,7 +751,7 @@ begin
|
|||||||
valueCount := 0;
|
valueCount := 0;
|
||||||
|
|
||||||
Result :=
|
Result :=
|
||||||
function(const Value: TOhlcItem): TStochastic.TResult
|
function(const Value: TArgs): TStochastic.TResult
|
||||||
var
|
var
|
||||||
currentIndex, firstIndex, lastIndex: Integer;
|
currentIndex, firstIndex, lastIndex: Integer;
|
||||||
highestHigh, lowestLow: Double;
|
highestHigh, lowestLow: Double;
|
||||||
@@ -926,25 +929,25 @@ begin
|
|||||||
Result :=
|
Result :=
|
||||||
function(const Params: TParams): TConvertFunc<TArgs, TResult>
|
function(const Params: TParams): TConvertFunc<TArgs, TResult>
|
||||||
var
|
var
|
||||||
atrFunc: TConvertFunc<TOhlcItem, Double>;
|
atrFunc: TConvertFunc<TArgs, Double>;
|
||||||
begin
|
begin
|
||||||
atrFunc := CreateATR(Params.Period);
|
atrFunc := CreateATR(Params.Period);
|
||||||
Result := function(const Value: TArgs): TResult begin Result.ATR := atrFunc(Value.Value); end;
|
Result := function(const Value: TArgs): TResult begin Result.ATR := atrFunc(Value); end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class function TATR.CreateATR(Period: Integer): TConvertFunc<TOhlcItem, Double>;
|
class function TATR.CreateATR(Period: Integer): TConvertFunc<TArgs, Double>;
|
||||||
begin
|
begin
|
||||||
Result := CreateATR(TEMA.CreateEMA(Period));
|
Result := CreateATR(TEMA.CreateEMA(Period));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Calculates the Average True Range (ATR) using an injectable moving average.
|
// Calculates the Average True Range (ATR) using an injectable moving average.
|
||||||
class function TATR.CreateATR(const MovAvgTR: TConvertFunc<Double, Double>): TConvertFunc<TOhlcItem, Double>;
|
class function TATR.CreateATR(const MovAvgTR: TConvertFunc<Double, Double>): TConvertFunc<TArgs, Double>;
|
||||||
begin
|
begin
|
||||||
var sourceData: TSeries<TOhlcItem>;
|
var sourceData: TSeries<TArgs>;
|
||||||
|
|
||||||
Result :=
|
Result :=
|
||||||
function(const Value: TOhlcItem): Double
|
function(const Value: TArgs): Double
|
||||||
var
|
var
|
||||||
tr: Double;
|
tr: Double;
|
||||||
begin
|
begin
|
||||||
@@ -968,20 +971,19 @@ end;
|
|||||||
|
|
||||||
{ TKeltnerChannels }
|
{ TKeltnerChannels }
|
||||||
|
|
||||||
class function TKeltnerChannels.CreateFactory:
|
class function TKeltnerChannels.CreateFactory: TIndicatorFactoryProc<TParams, TArgs, TResult>;
|
||||||
TIndicatorFactoryProc<TKeltnerChannels.TParams, TKeltnerChannels.TArgs, TKeltnerChannels.TResult>;
|
|
||||||
begin
|
begin
|
||||||
Result :=
|
Result :=
|
||||||
function(const Params: TParams): TConvertFunc<TArgs, TResult>
|
function(const Params: TParams): TConvertFunc<TArgs, TResult>
|
||||||
var
|
var
|
||||||
kcFunc: TConvertFunc<TOhlcItem, TResult>;
|
kcFunc: TConvertFunc<TArgs, TResult>;
|
||||||
begin
|
begin
|
||||||
kcFunc := CreateKeltnerChannels(Params.Period, Params.Multiplier);
|
kcFunc := CreateKeltnerChannels(Params.Period, Params.Multiplier);
|
||||||
Result := function(const Value: TArgs): TResult begin Result := kcFunc(Value.Value); end;
|
Result := function(const Value: TArgs): TResult begin Result := kcFunc(Value); end;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class function TKeltnerChannels.CreateKeltnerChannels(Period: Integer; Multiplier: Double): TConvertFunc<TOhlcItem, TResult>;
|
class function TKeltnerChannels.CreateKeltnerChannels(Period: Integer; Multiplier: Double): TConvertFunc<TArgs, TResult>;
|
||||||
begin
|
begin
|
||||||
Result := CreateKeltnerChannels(TEMA.CreateEMA(Period), TATR.CreateATR(Period), Multiplier);
|
Result := CreateKeltnerChannels(TEMA.CreateEMA(Period), TATR.CreateATR(Period), Multiplier);
|
||||||
end;
|
end;
|
||||||
@@ -989,12 +991,12 @@ end;
|
|||||||
// Calculates Keltner Channels using an injectable ATR and middle band moving average.
|
// Calculates Keltner Channels using an injectable ATR and middle band moving average.
|
||||||
class function TKeltnerChannels.CreateKeltnerChannels(
|
class function TKeltnerChannels.CreateKeltnerChannels(
|
||||||
const MovAvgMiddle: TConvertFunc<Double, Double>;
|
const MovAvgMiddle: TConvertFunc<Double, Double>;
|
||||||
const AtrFunc: TConvertFunc<TOhlcItem, Double>;
|
const AtrFunc: TConvertFunc<TATR.TArgs, Double>;
|
||||||
Multiplier: Double
|
Multiplier: Double
|
||||||
): TConvertFunc<TOhlcItem, TKeltnerChannels.TResult>;
|
): TConvertFunc<TArgs, TKeltnerChannels.TResult>;
|
||||||
begin
|
begin
|
||||||
Result :=
|
Result :=
|
||||||
function(const Value: TOhlcItem): TKeltnerChannels.TResult
|
function(const Value: TArgs): TKeltnerChannels.TResult
|
||||||
var
|
var
|
||||||
atrValue, middleValue, typicalPrice: Double;
|
atrValue, middleValue, typicalPrice: Double;
|
||||||
begin
|
begin
|
||||||
@@ -1003,7 +1005,12 @@ begin
|
|||||||
|
|
||||||
// Get values from the provided indicator functions.
|
// Get values from the provided indicator functions.
|
||||||
middleValue := MovAvgMiddle(typicalPrice);
|
middleValue := MovAvgMiddle(typicalPrice);
|
||||||
atrValue := AtrFunc(Value);
|
|
||||||
|
var atrArgs: TATR.TArgs;
|
||||||
|
atrArgs.High := Value.High;
|
||||||
|
atrArgs.Low := Value.Low;
|
||||||
|
atrArgs.Close := Value.Close;
|
||||||
|
atrValue := AtrFunc(atrArgs);
|
||||||
|
|
||||||
// Set default NaN values for the warm-up period.
|
// Set default NaN values for the warm-up period.
|
||||||
Result.MiddleBand := middleValue;
|
Result.MiddleBand := middleValue;
|
||||||
@@ -1064,6 +1071,6 @@ initialization
|
|||||||
IndicatorRegistry.RegisterTemplate<TBollingerBands>;
|
IndicatorRegistry.RegisterTemplate<TBollingerBands>;
|
||||||
IndicatorRegistry.RegisterTemplate<TATR>;
|
IndicatorRegistry.RegisterTemplate<TATR>;
|
||||||
IndicatorRegistry.RegisterTemplate<TKeltnerChannels>;
|
IndicatorRegistry.RegisterTemplate<TKeltnerChannels>;
|
||||||
IndicatorRegistry.RegisterTemplate<TMean>;
|
// IndicatorRegistry.RegisterTemplate<TMean>;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|||||||
Reference in New Issue
Block a user