Refactoring DataFlow, 1st Generic Data records working
This commit is contained in:
@@ -5,6 +5,9 @@ interface
|
||||
uses
|
||||
System.SysUtils,
|
||||
System.Math,
|
||||
System.Generics.Collections,
|
||||
System.Rtti,
|
||||
Myc.DataRecord,
|
||||
Myc.Trade.Types,
|
||||
Myc.Trade.DataArray;
|
||||
|
||||
@@ -78,8 +81,72 @@ type
|
||||
const AtrFunc: TConstFunc<TOhlcItem, Double>;
|
||||
Multiplier: Double
|
||||
): TConstFunc<TOhlcItem, TKeltnerChannelsResult>; overload; static;
|
||||
|
||||
class function CreateMean: TConstFunc<TArray<Double>, Double>; static;
|
||||
end;
|
||||
|
||||
TIndicatorFactory = class
|
||||
type
|
||||
TFunc = TConstFunc<TDataRecord, TDataRecord>;
|
||||
private
|
||||
FParams: TDataRecord.TLayout;
|
||||
FInput: TDataRecord.TLayout;
|
||||
FOutput: TDataRecord.TLayout;
|
||||
|
||||
public
|
||||
constructor Create(const AParams, AInput, AOutput: TDataRecord.TLayout);
|
||||
|
||||
function CreateIndicator(const Params: TDataRecord): TFunc; virtual; abstract;
|
||||
|
||||
property Params: TDataRecord.TLayout read FParams;
|
||||
property Input: TDataRecord.TLayout read FInput;
|
||||
property Output: TDataRecord.TLayout read FOutput;
|
||||
end;
|
||||
|
||||
TEMA = class(TIndicatorFactory)
|
||||
type
|
||||
TParam = record
|
||||
Period: Integer;
|
||||
end;
|
||||
|
||||
TInput = record
|
||||
Price: Double;
|
||||
end;
|
||||
|
||||
TResult = record
|
||||
MA: Double;
|
||||
end;
|
||||
|
||||
public
|
||||
constructor Create;
|
||||
function CreateIndicator(const Params: TDataRecord): TIndicatorFactory.TFunc; override;
|
||||
end;
|
||||
|
||||
TMACD = class
|
||||
type
|
||||
TParam = record
|
||||
Fast: TConstFunc<Double, Double>;
|
||||
Slow: TConstFunc<Double, Double>;
|
||||
Signal: TConstFunc<Double, Double>;
|
||||
end;
|
||||
|
||||
TInput = record
|
||||
Price: Double;
|
||||
end;
|
||||
|
||||
TResult = record
|
||||
MacdLine: Double;
|
||||
SignalLine: Double;
|
||||
Histogram: Double;
|
||||
end;
|
||||
|
||||
public
|
||||
class function CreateMACD(const Param: TParam): TConstFunc<TInput, TResult>; static;
|
||||
end;
|
||||
|
||||
var
|
||||
Registry: TList<TIndicatorFactory>;
|
||||
|
||||
implementation
|
||||
|
||||
{ TIndicators }
|
||||
@@ -466,4 +533,93 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
class function TIndicators.CreateMean: TConstFunc<TArray<Double>, Double>;
|
||||
begin
|
||||
Result :=
|
||||
function(const Value: TArray<Double>): Double
|
||||
begin
|
||||
if Length(Value) = 0 then
|
||||
exit(NaN);
|
||||
Result := Value[0];
|
||||
for var i := 1 to High(Value) do
|
||||
Result := Result + Value[i];
|
||||
Result := Result / Length(Value);
|
||||
end;
|
||||
end;
|
||||
|
||||
// Creates a MACD indicator from three provided moving average functions.
|
||||
class function TMACD.CreateMACD(const Param: TParam): TConstFunc<TInput, TResult>;
|
||||
begin
|
||||
Result :=
|
||||
function(const Input: TInput): TResult
|
||||
var
|
||||
fastVal, slowVal: Double;
|
||||
begin
|
||||
fastVal := Param.Fast(Input.Price);
|
||||
slowVal := Param.Slow(Input.Price);
|
||||
|
||||
if IsNan(slowVal) then // slowVal will be the last one to become non-NaN
|
||||
begin
|
||||
Result.MacdLine := Double.NaN;
|
||||
Result.SignalLine := Double.NaN;
|
||||
Result.Histogram := Double.NaN;
|
||||
end
|
||||
else
|
||||
begin
|
||||
Result.MacdLine := fastVal - slowVal;
|
||||
Result.SignalLine := Param.Signal(Result.MacdLine);
|
||||
if not IsNan(Result.SignalLine) then
|
||||
Result.Histogram := Result.MacdLine - Result.SignalLine
|
||||
else
|
||||
Result.Histogram := Double.NaN;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
constructor TEMA.Create;
|
||||
begin
|
||||
inherited
|
||||
Create(TDataRecord.TLayout.CreateFrom<TParam>, TDataRecord.TLayout.CreateFrom<TInput>, TDataRecord.TLayout.CreateFrom<TResult>)
|
||||
end;
|
||||
|
||||
function TEMA.CreateIndicator(const Params: TDataRecord): TIndicatorFactory.TFunc;
|
||||
begin
|
||||
var Period := Params.GetValue<Integer>('Period');
|
||||
|
||||
var Input := TDataRecord.TLayout.CreateFrom<TInput>;
|
||||
var inPrice := Input.IndexOf('Price');
|
||||
|
||||
var Output := TDataRecord.TLayout.CreateFrom<TResult>;
|
||||
var outMA := Output.IndexOf('MA');
|
||||
|
||||
var CalcEMA := TIndicators.CreateEMA(Period);
|
||||
|
||||
Result :=
|
||||
function(const Input: TDataRecord): TDataRecord
|
||||
begin
|
||||
var Price: Double;
|
||||
Input.GetValue(inPrice, Price);
|
||||
|
||||
var MA := CalcEMA(Price);
|
||||
|
||||
Result := TDataRecord.CreateFrom(Output);
|
||||
Result.SetValue(outMA, MA);
|
||||
end;
|
||||
end;
|
||||
|
||||
constructor TIndicatorFactory.Create(const AParams, AInput, AOutput: TDataRecord.TLayout);
|
||||
begin
|
||||
inherited Create;
|
||||
FParams := AParams;
|
||||
FInput := AInput;
|
||||
FOutput := AOutput;
|
||||
end;
|
||||
|
||||
initialization
|
||||
Registry := TList<TIndicatorFactory>.Create;
|
||||
Registry.Add(TEMA.Create);
|
||||
|
||||
finalization
|
||||
Registry.Free;
|
||||
|
||||
end.
|
||||
|
||||
Reference in New Issue
Block a user