Refactoring DataFlow, 1st Generic Data records working

This commit is contained in:
Michael Schimmel
2025-07-22 01:13:01 +02:00
parent dd50049b06
commit bf4ef71cba
11 changed files with 1074 additions and 907 deletions
+243 -11
View File
@@ -50,7 +50,9 @@ uses
System.Actions,
FMX.ActnList,
DynamicFMXControl,
Myc.FMX.Chart;
Myc.FMX.Chart,
Myc.Trade.Indicators,
Myc.DataRecord;
type
TForm1 = class(TForm)
@@ -108,6 +110,7 @@ type
procedure NewWorkspace;
function CurrLayout<T: TControl>: T;
procedure AlignControl(Control: TControl);
function CreateStrategy1(Timeframe: TTimeframe): IMycProcessor<TDataPoint<TOhlcItem>>;
function CreateStrategy2(Timeframe: TTimeframe): IMycProcessor<TDataPoint<TOhlcItem>>;
published
@@ -124,29 +127,24 @@ type
constructor Create(AEquity: Double);
end;
type
TStaget1Result = record
ATR, Hull, SMA, O, H, L, C: Double
end;
var
Form1: TForm1;
implementation
uses
TestModule,
Myc.Trade.Indicators,
Myc.DataRecord;
TestModule;
{$R *.fmx}
procedure TForm1.NewWorkspace;
var
tab: TTabItem;
begin
var ws: IAuraWorkspace := TMycAuraWorkspace.Create('New workspace', tmTesting);
FApplication.Workspaces.Insert(-1, ws);
var tab := TabControl.Add;
tab := TabControl.Add;
tab.Text := ws.Caption;
tab.Tag := NativeInt(ws);
@@ -297,7 +295,7 @@ begin
Control.Align := TAlignLayout.Top;
end;
function TForm1.CreateStrategy2(Timeframe: TTimeframe): IMycProcessor<TDataPoint<TOhlcItem>>;
function TForm1.CreateStrategy1(Timeframe: TTimeframe): IMycProcessor<TDataPoint<TOhlcItem>>;
type
TSignal = record
Sig: Double;
@@ -453,6 +451,12 @@ begin
panel.AddDoubleSeries(Signal.Field<Double>('Entry').Sender, TAlphaColors.Green, 1);
panel.AddDoubleSeries(Signal.Field<Double>('SL').Sender, TAlphaColors.Red, 2);
var mean := TConverter<TArray<Double>, Double>.CreateGeneric(TIndicators.CreateMean());
TConverter.Join<Double>([Hull.Sender, Sma.Sender]).Link(mean);
panel.AddDoubleSeries(mean.Sender, TAlphaColors.Blue, 5);
var pnlChart := TMycChart.Create(Self);
AlignControl(pnlChart);
pnlChart.Height := Layout.ChildrenRect.Width * 9 / 24;
@@ -460,8 +464,236 @@ begin
pnlChart.SetXAxisCounter<Double>(equity.Sender);
////////////
var EMAFactory := TEMA.Create;
var Params := TDataRecord.CreateFrom(EMAFactory.Params);
Params.SetValue<Integer>('Period', 20);
var indi := EMAFActory.CreateIndicator(Params);
var EMAConv := TConverter<TDataRecord, TDataRecord>.CreateGeneric(indi);
var equityEMA :=
equity
.Chain<TDataRecord>(TConverter.FieldToRecord<Double>(EMAFactory.Input, 'Price'))
.Chain<TDataRecord>(EMAConv)
.Chain<Double>(TConverter.FieldOfRecord<Double>(EMAFactory.Output, 'MA'));
//////////////
panel := pnlChart.AddPanel;
panel.AddDoubleSeries(equity.Sender, TAlphaColors.Blue, 3);
panel.AddDoubleSeries(equityEMA.Sender, TAlphaColors.Gray, 2);
/////
end;
function TForm1.CreateStrategy2(Timeframe: TTimeframe): IMycProcessor<TDataPoint<TOhlcItem>>;
type
TSignal = record
Sig: Double;
SL: Double;
Entry: Double;
pnl: Double;
end;
var
panel: TMycChart.TPanel;
begin
var ticker := TConverter.CreateIdentity<TDataPoint<TOhlcItem>>;
Result := ticker;
var OhlcPoint := ticker.Chain<TDataPoint<TOhlcItem>>(TConverter.CreateOhlcAggregation(Timeframe));
var Ohlc := OhlcPoint.Field<TOhlcItem>('Data');
var Closes := Ohlc.Field<Double>('Close');
var Hull := Closes.Chain<Double>(TIndicators.CreateHMA(250)).MakeParallel;
var Sma := Closes.Chain<Double>(TIndicators.CreateSMA(200)).MakeParallel;
var Lowest: Double := Double.MaxValue;
var Highest: Double := Double.MinValue;
var ATR := Ohlc.Chain<Double>(TIndicators.CreateATR(50)).MakeParallel;
// next stage
var ATREndPoint := TConverter.CreateEndpoint<Double>(ATR.Sender, 5);
var ATRSeries: TSeries<Double>;
var HullEndPoint := TConverter.CreateEndpoint<Double>(Hull.Sender, 5);
var HullSeries: TSeries<Double>;
var SmaEndPoint := TConverter.CreateEndpoint<Double>(Sma.Sender, 5);
var SmaSeries: TSeries<Double>;
var curr: TSignal;
curr.SL := Double.NaN;
curr.Entry := Double.NaN;
var lastHull, lastSma: Double;
var conv :=
TConverter.Join<Double>(
[Ohlc.Field<Double>('Low').Sender, Ohlc.Field<Double>('High').Sender, Closes.Sender, ATR.Sender, Hull.Sender, Sma.Sender]
);
var Signal :=
TConverter<TArray<Double>, TSignal>.CreateGeneric(
function(const Values: TArray<Double>): TSignal
begin
var low := Values[0];
var high := Values[1];
var close := Values[2];
var atr := Values[3];
var hull := Values[4];
var sma := Values[5];
if low < Lowest then
Lowest := low;
if high > Highest then
Highest := high;
Result := curr;
Result.Sig := 0;
var pnl: double := NaN;
if (hull < sma) and (lastHull >= lastSma) then
begin
if curr.Sig > 0 then
pnl := close - curr.Entry;
curr.Sig := -1;
curr.SL := Highest;
curr.Entry := close;
Result := curr;
end
else if (hull > sma) and (lastHull <= lastSma) then
begin
if curr.Sig < 0 then
pnl := curr.Entry - close;
curr.Sig := 1;
curr.SL := Lowest;
curr.Entry := close;
Result := curr;
end;
atr := 15 * atr;
if curr.Sig > 0 then
begin
if close > curr.SL then
begin
if curr.SL < close - atr then
curr.SL := close - atr;
Result.SL := curr.SL;
end;
if low <= curr.SL then
begin
pnl := curr.SL - curr.Entry;
curr.Sig := 0;
Result.Sig := 0;
curr.SL := NaN;
end;
end
else if curr.Sig < 0 then
begin
if close < curr.SL then
begin
if curr.SL > close + atr then
curr.SL := close + atr;
Result.SL := curr.SL;
end;
if high >= curr.SL then
begin
pnl := curr.Entry - curr.SL;
curr.Sig := 0;
Result.Sig := 0;
curr.SL := NaN;
end;
end;
if Result.Sig <> 0 then
begin
Lowest := Double.MaxValue;
Highest := Double.MinValue;
Result.SL := Double.NaN;
Result.Entry := Double.NaN;
end;
Result.pnl := pnl;
lastHull := hull;
lastSma := sma;
end
);
conv.Link(Signal);
var pnl := Signal.Field<Double>('pnl');
var equity: TConverter<Double, Double> := TEquitySum.Create(10000);
pnl.Sender.Link(equity);
var Layout := CurrLayout<TVertScrollBox>;
if Layout = nil then
exit;
var Symbol := SelectedSymbol;
if Symbol = '' then
exit;
var chart := TMycChart.Create(Self);
AlignControl(chart);
chart.Height := Layout.ChildrenRect.Width * 9 / 16;
chart.Lookback.Value := 50000;
chart.SetXAxisSeries(M15, OhlcPoint.Field<TDateTime>('Time').Sender);
panel := chart.AddPanel;
panel.AddOhlcSeries(Ohlc.Sender);
panel.AddDoubleSeries(Hull.Sender, TAlphaColors.Cornflowerblue, 2);
panel.AddDoubleSeries(Sma.Sender, TAlphaColors.Brown, 1.5);
panel.AddDoubleSeries(Signal.Field<Double>('Entry').Sender, TAlphaColors.Green, 1);
panel.AddDoubleSeries(Signal.Field<Double>('SL').Sender, TAlphaColors.Red, 2);
var mean := TConverter<TArray<Double>, Double>.CreateGeneric(TIndicators.CreateMean());
TConverter.Join<Double>([Hull.Sender, Sma.Sender]).Link(mean);
panel.AddDoubleSeries(mean.Sender, TAlphaColors.Blue, 5);
var pnlChart := TMycChart.Create(Self);
AlignControl(pnlChart);
pnlChart.Height := Layout.ChildrenRect.Width * 9 / 24;
pnlChart.Lookback.Value := 50000;
pnlChart.SetXAxisCounter<Double>(equity.Sender);
////////////
var EMAFactory := TEMA.Create;
var Params := TDataRecord.CreateFrom(EMAFactory.Params);
Params.SetValue<Integer>('Period', 20);
var indi := EMAFActory.CreateIndicator(Params);
var EMAConv := TConverter<TDataRecord, TDataRecord>.CreateGeneric(indi);
var equityEMA :=
equity
.Chain<TDataRecord>(TConverter.FieldToRecord<Double>(EMAFactory.Input, 'Price'))
.Chain<TDataRecord>(EMAConv)
.Chain<Double>(TConverter.FieldOfRecord<Double>(EMAFactory.Output, 'MA'));
//////////////
panel := pnlChart.AddPanel;
panel.AddDoubleSeries(equity.Sender, TAlphaColors.Blue, 3);
panel.AddDoubleSeries(equityEMA.Sender, TAlphaColors.Gray, 2);
/////
end;