From e4681e2bf7b6be5b1cb275af190f40c1ab62daab Mon Sep 17 00:00:00 2001 From: Michael Schimmel Date: Mon, 25 Aug 2025 20:18:38 +0200 Subject: [PATCH] Aura types --- Src/Data/Myc.Data.Types.Method.pas | 3 - Src/Myc.Trade.Indicators.Common.pas | 590 ++++++++++++++++++++++++++++ 2 files changed, 590 insertions(+), 3 deletions(-) diff --git a/Src/Data/Myc.Data.Types.Method.pas b/Src/Data/Myc.Data.Types.Method.pas index 14112e4..a83c5f7 100644 --- a/Src/Data/Myc.Data.Types.Method.pas +++ b/Src/Data/Myc.Data.Types.Method.pas @@ -9,7 +9,6 @@ uses type // Implements the IDataMethodType interface. - // This class is now instantiated for each unique method signature. TDataMethodType = class(TInterfacedObject, IDataMethodType) private FArgType: IDataType; @@ -20,7 +19,6 @@ type function GetResultType: IDataType; function CreateValue(const AValue: TMethodProc): IDataMethodValue; public - // The constructor now takes the signature types. constructor Create(const AArgType, AResultType: IDataType); end; @@ -57,7 +55,6 @@ begin if not Assigned(AValue) then raise EArgumentException.Create('AValue'); - // Pass Self to the value's constructor, so it knows its exact type Result := TDataMethodValue.Create(Self, AValue); end; diff --git a/Src/Myc.Trade.Indicators.Common.pas b/Src/Myc.Trade.Indicators.Common.pas index d257bf7..c3da24a 100644 --- a/Src/Myc.Trade.Indicators.Common.pas +++ b/Src/Myc.Trade.Indicators.Common.pas @@ -9,6 +9,7 @@ uses Myc.Data.Records, Myc.Data.Pipeline, Myc.Data.Series, + Myc.Data.Types, Myc.Trade.Types, Myc.Trade.Indicators; @@ -18,6 +19,10 @@ type [IndicatorName('SMA', 'Simple Moving Average')] [IndicatorHint('Calculates the average of a selected range of prices.')] TSMA = class + strict private + class var + FFactory: IDataMethodValue; + class constructor CreateClass; public type TParams = record @@ -32,11 +37,18 @@ type [IndicatorFactory] class function CreateFactory: TIndicatorFactoryProc; static; class function CreateSMA(Period: Integer): TConvertFunc; static; + + // Provides the factory method for this indicator as a data value. + class property Factory: IDataMethodValue read FFactory; end; [IndicatorName('EMA', 'Exponential Moving Average')] [IndicatorHint('A moving average that places greater weight on the most recent data points.')] TEMA = class + strict private + class var + FFactory: IDataMethodValue; + class constructor CreateClass; public type TParams = record @@ -51,11 +63,17 @@ type [IndicatorFactory] class function CreateFactory: TIndicatorFactoryProc; static; class function CreateEMA(Period: Integer): TConvertFunc; static; + // Provides the factory method for this indicator as a data value. + class property Factory: IDataMethodValue read FFactory; end; [IndicatorName('WMA', 'Weighted Moving Average')] [IndicatorHint('A moving average that places greater weight on more recent data points.')] TWMA = class + strict private + class var + FFactory: IDataMethodValue; + class constructor CreateClass; public type TParams = record @@ -70,11 +88,17 @@ type [IndicatorFactory] class function CreateFactory: TIndicatorFactoryProc; static; class function CreateWMA(Period: Integer): TConvertFunc; static; + // Provides the factory method for this indicator as a data value. + class property Factory: IDataMethodValue read FFactory; end; [IndicatorName('HMA', 'Hull Moving Average')] [IndicatorHint('A fast, smooth moving average that minimizes lag.')] THMA = class + strict private + class var + FFactory: IDataMethodValue; + class constructor CreateClass; public type TParams = record @@ -89,11 +113,17 @@ type [IndicatorFactory] class function CreateFactory: TIndicatorFactoryProc; static; class function CreateHMA(Period: Integer): TConvertFunc; static; + // Provides the factory method for this indicator as a data value. + class property Factory: IDataMethodValue read FFactory; end; [IndicatorName('RSI', 'Relative Strength Index')] [IndicatorHint('A momentum indicator measuring the magnitude of recent price changes.')] TRSI = class + strict private + class var + FFactory: IDataMethodValue; + class constructor CreateClass; public type TParams = record @@ -108,11 +138,17 @@ type [IndicatorFactory] class function CreateFactory: TIndicatorFactoryProc; static; class function CreateRSI(Period: Integer): TConvertFunc; static; + // Provides the factory method for this indicator as a data value. + class property Factory: IDataMethodValue read FFactory; end; [IndicatorName('MACD', 'Moving Average Convergence Divergence')] [IndicatorHint('A trend-following momentum indicator showing the relationship between two EMAs.')] TMACD = class + strict private + class var + FFactory: IDataMethodValue; + class constructor CreateClass; public type TParams = record @@ -136,11 +172,17 @@ type EmaSlow, EmaSignal: TConvertFunc ): TConvertFunc; overload; static; + // Provides the factory method for this indicator as a data value. + class property Factory: IDataMethodValue read FFactory; end; [IndicatorName('Stoch', 'Stochastic Oscillator')] [IndicatorHint('A momentum indicator comparing a closing price to a range of its prices.')] TStochastic = class + strict private + class var + FFactory: IDataMethodValue; + class constructor CreateClass; public type TParams = record @@ -162,11 +204,17 @@ type KPeriod: Integer; const SmaD: TConvertFunc ): TConvertFunc; overload; static; + // Provides the factory method for this indicator as a data value. + class property Factory: IDataMethodValue read FFactory; end; [IndicatorName('StdDev', 'Standard Deviation')] [IndicatorHint('Measures the amount of variation or dispersion of a set of values.')] TStdDev = class + strict private + class var + FFactory: IDataMethodValue; + class constructor CreateClass; public type TParams = record @@ -181,11 +229,17 @@ type [IndicatorFactory] class function CreateFactory: TIndicatorFactoryProc; static; class function CreateStdDev(Period: Integer): TConvertFunc; static; + // Provides the factory method for this indicator as a data value. + class property Factory: IDataMethodValue read FFactory; end; [IndicatorName('BB', 'Bollinger Bands')] [IndicatorHint('Characterizes prices and volatility over time using standard deviation bands.')] TBollingerBands = class + strict private + class var + FFactory: IDataMethodValue; + class constructor CreateClass; public type TParams = record @@ -203,11 +257,17 @@ type [IndicatorFactory] class function CreateFactory: TIndicatorFactoryProc; static; class function CreateBollingerBands(Period: Integer; Multiplier: Double): TConvertFunc; static; + // Provides the factory method for this indicator as a data value. + class property Factory: IDataMethodValue read FFactory; end; [IndicatorName('ATR', 'Average True Range')] [IndicatorHint('Measures market volatility by decomposing the entire range of an asset price.')] TATR = class + strict private + class var + FFactory: IDataMethodValue; + class constructor CreateClass; public type TParams = record @@ -223,11 +283,17 @@ type class function CreateFactory: TIndicatorFactoryProc; static; class function CreateATR(Period: Integer): TConvertFunc; overload; static; class function CreateATR(const MovAvgTR: TConvertFunc): TConvertFunc; overload; static; + // Provides the factory method for this indicator as a data value. + class property Factory: IDataMethodValue read FFactory; end; [IndicatorName('KC', 'Keltner Channels')] [IndicatorHint('A volatility-based indicator composed of an EMA and two ATR-based outer lines.')] TKeltnerChannels = class + strict private + class var + FFactory: IDataMethodValue; + class constructor CreateClass; public type TParams = record @@ -250,11 +316,17 @@ type const AtrFunc: TConvertFunc; Multiplier: Double ): TConvertFunc; overload; static; + // Provides the factory method for this indicator as a data value. + class property Factory: IDataMethodValue read FFactory; end; [IndicatorName('Mean', 'Mean Value')] [IndicatorHint('Calculates the arithmetic mean of an array of values.')] TMean = class + strict private + class var + FFactory: IDataMethodValue; + class constructor CreateClass; public type TParams = record @@ -268,12 +340,73 @@ type [IndicatorFactory] class function CreateFactory: TIndicatorFactoryProc; static; class function CreateMean: TConvertFunc, Double>; static; + // Provides the factory method for this indicator as a data value. + class property Factory: IDataMethodValue read FFactory; end; implementation { TSMA } +class constructor TSMA.CreateClass; +begin + { var params := TDataType.RecordOf( [TRecordField.Create( 'Period', TDataType.Ordinal )] ); + var args := TDataType.RecordOf( [TRecordField.Create( 'Value', TDataType.Float )] ); + var results := TDataType.RecordOf( [TRecordField.Create( 'SMA', TDataType.Float )] ); + + var indicatorMethod := TDataType.MethodOf( args, results ); + var factoryMethod := TDataType.MethodOf( params, indicatorMethod ); + + FFactory := factoryMethod.CreateValue( + function( const Params: IDataValue ): IDataValue + begin + var period := TDataValue(TDataValue(Params).AsRecord.Items[0]).AsOrdinal.Value; + + var SMA := CreateSMA( period ); + + Result := indicatorMethod.CreateValue( + function( const Args: IDataValue ): IDataValue + begin + var value := TDataValue(TDataValue(Args).AsRecord.Items[0]).AsFloat.Value; + + var res := SMA( value ); + + Result := results.CreateValue( [TDataValue.FromFloat(res)] ); + end ); + end ); +} + + // ....or.... + var params := TDataType.Ordinal; + var args := TDataType.Float; + var results := TDataType.Float; + + var indicatorMethod := TDataType.MethodOf(args, results); + var factoryMethod := TDataType.MethodOf(params, indicatorMethod); + + FFactory := + factoryMethod.CreateValue( + function(const Params: IDataValue): IDataValue + begin + var period := TDataValue(Params).AsOrdinal.Value; + + var SMA := CreateSMA(period); + + Result := + indicatorMethod.CreateValue( + function(const Args: IDataValue): IDataValue + begin + var value := TDataValue(Args).AsFloat.Value; + + var res := SMA(value); + + Result := results.CreateValue(res); + end + ); + end + ); +end; + class function TSMA.CreateFactory: TIndicatorFactoryProc; begin Result := @@ -348,6 +481,36 @@ end; { TEMA } +class constructor TEMA.CreateClass; +begin + var params := TDataType.RecordOf([TRecordField.Create('Period', TDataType.Ordinal)]); + var args := TDataType.RecordOf([TRecordField.Create('Value', TDataType.Float)]); + var results := TDataType.RecordOf([TRecordField.Create('EMA', TDataType.Float)]); + + var indicatorMethod := TDataType.MethodOf(args, results); + var factoryMethod := TDataType.MethodOf(params, indicatorMethod); + + FFactory := + factoryMethod.CreateValue( + function(const Params: IDataValue): IDataValue + begin + var period := TDataValue(TDataValue(Params).AsRecord.Items[0]).AsOrdinal.Value; + + var EMA := CreateEMA(period); + + Result := + indicatorMethod.CreateValue( + function(const Args: IDataValue): IDataValue + begin + var value := TDataValue(TDataValue(Args).AsRecord.Items[0]).AsFloat.Value; + var res := EMA(value); + Result := results.CreateValue([TDataValue.FromFloat(res)]); + end + ); + end + ); +end; + class function TEMA.CreateFactory: TIndicatorFactoryProc; begin Result := @@ -406,6 +569,34 @@ end; { TWMA } +class constructor TWMA.CreateClass; +begin + var params := TDataType.RecordOf([TRecordField.Create('Period', TDataType.Ordinal)]); + var args := TDataType.RecordOf([TRecordField.Create('Value', TDataType.Float)]); + var results := TDataType.RecordOf([TRecordField.Create('WMA', TDataType.Float)]); + + var indicatorMethod := TDataType.MethodOf(args, results); + var factoryMethod := TDataType.MethodOf(params, indicatorMethod); + + FFactory := + factoryMethod.CreateValue( + function(const Params: IDataValue): IDataValue + begin + var period := TDataValue(TDataValue(Params).AsRecord.Items[0]).AsOrdinal.Value; + var WMA := CreateWMA(period); + Result := + indicatorMethod.CreateValue( + function(const Args: IDataValue): IDataValue + begin + var value := TDataValue(TDataValue(Args).AsRecord.Items[0]).AsFloat.Value; + var res := WMA(value); + Result := results.CreateValue([TDataValue.FromFloat(res)]); + end + ); + end + ); +end; + class function TWMA.CreateFactory: TIndicatorFactoryProc; begin Result := @@ -476,6 +667,34 @@ end; { THMA } +class constructor THMA.CreateClass; +begin + var params := TDataType.RecordOf([TRecordField.Create('Period', TDataType.Ordinal)]); + var args := TDataType.RecordOf([TRecordField.Create('Value', TDataType.Float)]); + var results := TDataType.RecordOf([TRecordField.Create('HMA', TDataType.Float)]); + + var indicatorMethod := TDataType.MethodOf(args, results); + var factoryMethod := TDataType.MethodOf(params, indicatorMethod); + + FFactory := + factoryMethod.CreateValue( + function(const Params: IDataValue): IDataValue + begin + var period := TDataValue(TDataValue(Params).AsRecord.Items[0]).AsOrdinal.Value; + var HMA := CreateHMA(period); + Result := + indicatorMethod.CreateValue( + function(const Args: IDataValue): IDataValue + begin + var value := TDataValue(TDataValue(Args).AsRecord.Items[0]).AsFloat.Value; + var res := HMA(value); + Result := results.CreateValue([TDataValue.FromFloat(res)]); + end + ); + end + ); +end; + class function THMA.CreateFactory: TIndicatorFactoryProc; begin Result := @@ -519,6 +738,34 @@ end; { TRSI } +class constructor TRSI.CreateClass; +begin + var params := TDataType.RecordOf([TRecordField.Create('Period', TDataType.Ordinal)]); + var args := TDataType.RecordOf([TRecordField.Create('Value', TDataType.Float)]); + var results := TDataType.RecordOf([TRecordField.Create('RSI', TDataType.Float)]); + + var indicatorMethod := TDataType.MethodOf(args, results); + var factoryMethod := TDataType.MethodOf(params, indicatorMethod); + + FFactory := + factoryMethod.CreateValue( + function(const Params: IDataValue): IDataValue + begin + var period := TDataValue(TDataValue(Params).AsRecord.Items[0]).AsOrdinal.Value; + var RSI := CreateRSI(period); + Result := + indicatorMethod.CreateValue( + function(const Args: IDataValue): IDataValue + begin + var value := TDataValue(TDataValue(Args).AsRecord.Items[0]).AsFloat.Value; + var res := RSI(value); + Result := results.CreateValue([TDataValue.FromFloat(res)]); + end + ); + end + ); +end; + class function TRSI.CreateFactory: TIndicatorFactoryProc; begin Result := @@ -592,6 +839,61 @@ end; { TMACD } +class constructor TMACD.CreateClass; +begin + var params := + TDataType.RecordOf( + [ + TRecordField.Create('FastPeriod', TDataType.Ordinal), + TRecordField.Create('SlowPeriod', TDataType.Ordinal), + TRecordField.Create('SignalPeriod', TDataType.Ordinal) + ] + ); + var args := TDataType.RecordOf([TRecordField.Create('Value', TDataType.Float)]); + var results := + TDataType.RecordOf( + [ + TRecordField.Create('MacdLine', TDataType.Float), + TRecordField.Create('SignalLine', TDataType.Float), + TRecordField.Create('Histogram', TDataType.Float) + ] + ); + + var indicatorMethod := TDataType.MethodOf(args, results); + var factoryMethod := TDataType.MethodOf(params, indicatorMethod); + + FFactory := + factoryMethod.CreateValue( + function(const Params: IDataValue): IDataValue + var + paramsRec: IDataRecordValue; + begin + paramsRec := TDataValue(Params).AsRecord; + var fastPeriod := TDataValue(paramsRec.Items[0]).AsOrdinal.Value; + var slowPeriod := TDataValue(paramsRec.Items[1]).AsOrdinal.Value; + var signalPeriod := TDataValue(paramsRec.Items[2]).AsOrdinal.Value; + var MACD := CreateMACD(fastPeriod, slowPeriod, signalPeriod); + + Result := + indicatorMethod.CreateValue( + function(const Args: IDataValue): IDataValue + begin + var value := TDataValue(TDataValue(Args).AsRecord.Items[0]).AsFloat.Value; + var res := MACD(value); + Result := + results.CreateValue( + [ + TDataValue.FromFloat(res.MacdLine), + TDataValue.FromFloat(res.SignalLine), + TDataValue.FromFloat(res.Histogram) + ] + ); + end + ); + end + ); +end; + class function TMACD.CreateFactory: TIndicatorFactoryProc; begin Result := @@ -703,6 +1005,64 @@ begin Result := FItems[FHead]; end; +class constructor TStochastic.CreateClass; +begin + var params := + TDataType.RecordOf([TRecordField.Create('KPeriod', TDataType.Ordinal), TRecordField.Create('DPeriod', TDataType.Ordinal)]); + + var ohlcType := + TDataType.RecordOf( + [ + TRecordField.Create('Open', TDataType.Float), + TRecordField.Create('High', TDataType.Float), + TRecordField.Create('Low', TDataType.Float), + TRecordField.Create('Close', TDataType.Float), + TRecordField.Create('Volume', TDataType.Float) + ] + ); + + var args := TDataType.RecordOf([TRecordField.Create('Value', ohlcType)]); + var results := TDataType.RecordOf([TRecordField.Create('K', TDataType.Float), TRecordField.Create('D', TDataType.Float)]); + + var indicatorMethod := TDataType.MethodOf(args, results); + var factoryMethod := TDataType.MethodOf(params, indicatorMethod); + + FFactory := + factoryMethod.CreateValue( + function(const Params: IDataValue): IDataValue + var + paramsRec: IDataRecordValue; + begin + paramsRec := TDataValue(Params).AsRecord; + var kPeriod := TDataValue(paramsRec.Items[0]).AsOrdinal.Value; + var dPeriod := TDataValue(paramsRec.Items[1]).AsOrdinal.Value; + var Stochastic := CreateStochastic(kPeriod, dPeriod); + + Result := + indicatorMethod.CreateValue( + function(const Args: IDataValue): IDataValue + var + argRec, ohlcRec: IDataRecordValue; + ohlcVal: TOhlcItem; + begin + argRec := TDataValue(Args).AsRecord; + ohlcRec := TDataValue(argRec.Items[0]).AsRecord; + + ohlcVal.Open := TDataValue(ohlcRec.Items[0]).AsFloat.Value; + ohlcVal.High := TDataValue(ohlcRec.Items[1]).AsFloat.Value; + ohlcVal.Low := TDataValue(ohlcRec.Items[2]).AsFloat.Value; + ohlcVal.Close := TDataValue(ohlcRec.Items[3]).AsFloat.Value; + ohlcVal.Volume := TDataValue(ohlcRec.Items[4]).AsFloat.Value; + + var res := Stochastic(ohlcVal); + + Result := results.CreateValue([TDataValue.FromFloat(res.K), TDataValue.FromFloat(res.D)]); + end + ); + end + ); +end; + class function TStochastic.CreateFactory: TIndicatorFactoryProc; begin Result := @@ -810,6 +1170,34 @@ end; { TStdDev } +class constructor TStdDev.CreateClass; +begin + var params := TDataType.RecordOf([TRecordField.Create('Period', TDataType.Ordinal)]); + var args := TDataType.RecordOf([TRecordField.Create('Value', TDataType.Float)]); + var results := TDataType.RecordOf([TRecordField.Create('StdDev', TDataType.Float)]); + + var indicatorMethod := TDataType.MethodOf(args, results); + var factoryMethod := TDataType.MethodOf(params, indicatorMethod); + + FFactory := + factoryMethod.CreateValue( + function(const Params: IDataValue): IDataValue + begin + var period := TDataValue(TDataValue(Params).AsRecord.Items[0]).AsOrdinal.Value; + var StdDev := CreateStdDev(period); + Result := + indicatorMethod.CreateValue( + function(const Args: IDataValue): IDataValue + begin + var value := TDataValue(TDataValue(Args).AsRecord.Items[0]).AsFloat.Value; + var res := StdDev(value); + Result := results.CreateValue([TDataValue.FromFloat(res)]); + end + ); + end + ); +end; + class function TStdDev.CreateFactory: TIndicatorFactoryProc; begin Result := @@ -875,6 +1263,54 @@ end; { TBollingerBands } +class constructor TBollingerBands.CreateClass; +begin + var params := + TDataType.RecordOf([TRecordField.Create('Period', TDataType.Ordinal), TRecordField.Create('Multiplier', TDataType.Float)]); + var args := TDataType.RecordOf([TRecordField.Create('Value', TDataType.Float)]); + var results := + TDataType.RecordOf( + [ + TRecordField.Create('UpperBand', TDataType.Float), + TRecordField.Create('MiddleBand', TDataType.Float), + TRecordField.Create('LowerBand', TDataType.Float) + ] + ); + + var indicatorMethod := TDataType.MethodOf(args, results); + var factoryMethod := TDataType.MethodOf(params, indicatorMethod); + + FFactory := + factoryMethod.CreateValue( + function(const Params: IDataValue): IDataValue + var + paramsRec: IDataRecordValue; + begin + paramsRec := TDataValue(Params).AsRecord; + var period := TDataValue(paramsRec.Items[0]).AsOrdinal.Value; + var multiplier := TDataValue(paramsRec.Items[1]).AsFloat.Value; + var BollingerBands := CreateBollingerBands(period, multiplier); + + Result := + indicatorMethod.CreateValue( + function(const Args: IDataValue): IDataValue + begin + var value := TDataValue(TDataValue(Args).AsRecord.Items[0]).AsFloat.Value; + var res := BollingerBands(value); + Result := + results.CreateValue( + [ + TDataValue.FromFloat(res.UpperBand), + TDataValue.FromFloat(res.MiddleBand), + TDataValue.FromFloat(res.LowerBand) + ] + ); + end + ); + end + ); +end; + class function TBollingerBands.CreateFactory: TIndicatorFactoryProc; begin @@ -921,6 +1357,55 @@ end; { TATR } +class constructor TATR.CreateClass; +begin + var params := TDataType.RecordOf([TRecordField.Create('Period', TDataType.Ordinal)]); + + var ohlcType := + TDataType.RecordOf( + [ + TRecordField.Create('Open', TDataType.Float), + TRecordField.Create('High', TDataType.Float), + TRecordField.Create('Low', TDataType.Float), + TRecordField.Create('Close', TDataType.Float), + TRecordField.Create('Volume', TDataType.Float) + ] + ); + var args := TDataType.RecordOf([TRecordField.Create('Value', ohlcType)]); + var results := TDataType.RecordOf([TRecordField.Create('ATR', TDataType.Float)]); + + var indicatorMethod := TDataType.MethodOf(args, results); + var factoryMethod := TDataType.MethodOf(params, indicatorMethod); + + FFactory := + factoryMethod.CreateValue( + function(const Params: IDataValue): IDataValue + begin + var period := TDataValue(TDataValue(Params).AsRecord.Items[0]).AsOrdinal.Value; + var ATR := CreateATR(period); + + Result := + indicatorMethod.CreateValue( + function(const Args: IDataValue): IDataValue + var + argRec, ohlcRec: IDataRecordValue; + ohlcVal: TOhlcItem; + begin + argRec := TDataValue(Args).AsRecord; + ohlcRec := TDataValue(argRec.Items[0]).AsRecord; + ohlcVal.Open := TDataValue(ohlcRec.Items[0]).AsFloat.Value; + ohlcVal.High := TDataValue(ohlcRec.Items[1]).AsFloat.Value; + ohlcVal.Low := TDataValue(ohlcRec.Items[2]).AsFloat.Value; + ohlcVal.Close := TDataValue(ohlcRec.Items[3]).AsFloat.Value; + ohlcVal.Volume := TDataValue(ohlcRec.Items[4]).AsFloat.Value; + var res := ATR(ohlcVal); + Result := results.CreateValue([TDataValue.FromFloat(res)]); + end + ); + end + ); +end; + class function TATR.CreateFactory: TIndicatorFactoryProc; begin Result := @@ -968,6 +1453,74 @@ end; { TKeltnerChannels } +class constructor TKeltnerChannels.CreateClass; +begin + var params := + TDataType.RecordOf([TRecordField.Create('Period', TDataType.Ordinal), TRecordField.Create('Multiplier', TDataType.Float)]); + var ohlcType := + TDataType.RecordOf( + [ + TRecordField.Create('Open', TDataType.Float), + TRecordField.Create('High', TDataType.Float), + TRecordField.Create('Low', TDataType.Float), + TRecordField.Create('Close', TDataType.Float), + TRecordField.Create('Volume', TDataType.Float) + ] + ); + var args := TDataType.RecordOf([TRecordField.Create('Value', ohlcType)]); + var results := + TDataType.RecordOf( + [ + TRecordField.Create('UpperBand', TDataType.Float), + TRecordField.Create('MiddleBand', TDataType.Float), + TRecordField.Create('LowerBand', TDataType.Float) + ] + ); + + var indicatorMethod := TDataType.MethodOf(args, results); + var factoryMethod := TDataType.MethodOf(params, indicatorMethod); + + FFactory := + factoryMethod.CreateValue( + function(const Params: IDataValue): IDataValue + var + paramsRec: IDataRecordValue; + begin + paramsRec := TDataValue(Params).AsRecord; + var period := TDataValue(paramsRec.Items[0]).AsOrdinal.Value; + var multiplier := TDataValue(paramsRec.Items[1]).AsFloat.Value; + var KeltnerChannels := CreateKeltnerChannels(period, multiplier); + + Result := + indicatorMethod.CreateValue( + function(const Args: IDataValue): IDataValue + var + argRec, ohlcRec: IDataRecordValue; + ohlcVal: TOhlcItem; + begin + argRec := TDataValue(Args).AsRecord; + ohlcRec := TDataValue(argRec.Items[0]).AsRecord; + ohlcVal.Open := TDataValue(ohlcRec.Items[0]).AsFloat.Value; + ohlcVal.High := TDataValue(ohlcRec.Items[1]).AsFloat.Value; + ohlcVal.Low := TDataValue(ohlcRec.Items[2]).AsFloat.Value; + ohlcVal.Close := TDataValue(ohlcRec.Items[3]).AsFloat.Value; + ohlcVal.Volume := TDataValue(ohlcRec.Items[4]).AsFloat.Value; + + var res := KeltnerChannels(ohlcVal); + Result := + results.CreateValue( + [ + TDataValue.FromFloat(res.UpperBand), + TDataValue.FromFloat(res.MiddleBand), + TDataValue.FromFloat(res.LowerBand) + ] + ); + end + ); + end + ); +end; + class function TKeltnerChannels.CreateFactory: TIndicatorFactoryProc; begin @@ -1021,6 +1574,43 @@ end; { TMean } +class constructor TMean.CreateClass; +begin + var params := TDataType.RecordOf([]); + var args := TDataType.RecordOf([TRecordField.Create('Values', TDataType.ArrayOf(TDataType.Float))]); + var results := TDataType.RecordOf([TRecordField.Create('Mean', TDataType.Float)]); + + var indicatorMethod := TDataType.MethodOf(args, results); + var factoryMethod := TDataType.MethodOf(params, indicatorMethod); + + FFactory := + factoryMethod.CreateValue( + function(const Params: IDataValue): IDataValue + begin + var Mean := CreateMean(); + Result := + indicatorMethod.CreateValue( + function(const Args: IDataValue): IDataValue + var + i: Integer; + argsRec: IDataRecordValue; + valuesArray: IDataArrayValue; + values: TArray; + begin + argsRec := TDataValue(Args).AsRecord; + valuesArray := TDataValue(argsRec.Items[0]).AsArray; + SetLength(values, valuesArray.ElementCount); + for i := 0 to valuesArray.ElementCount - 1 do + values[i] := TDataValue(valuesArray.Items[i]).AsFloat.Value; + + var res := Mean(values); + Result := results.CreateValue([TDataValue.FromFloat(res)]); + end + ); + end + ); +end; + class function TMean.CreateFactory: TIndicatorFactoryProc; begin Result :=