unit StrategyTest; interface uses Myc.Signals, Myc.Trade.Types, Myc.Trade.DataPoint, Myc.Trade.DataArray, Myc.DataRecord, Myc.Trade.Indicators; function CreateStrategy1(Timeframe: TTimeframe): TConverter, Double>; implementation uses System.SysUtils, System.Math; function CreateStrategy1(Timeframe: TTimeframe): TConverter, Double>; type TSignal = record Sig: Double; SL: Double; Entry: Double; pnl: Double; end; begin var ticker := TConverter.CreateIdentity>; var OhlcPoint := ticker.Chain>(TConverter.CreateOhlcAggregation(Timeframe)); var Ohlc := OhlcPoint.Field('Data'); var Closes := Ohlc.Field('Close'); var Hull := Closes.Chain(TIndicators.CreateHMA(250)).MakeParallel; var Sma := Closes.Chain(TIndicators.CreateSMA(200)).MakeParallel; var Lowest: Double := Double.MaxValue; var Highest: Double := Double.MinValue; var ATR := Ohlc.Chain(TIndicators.CreateATR(50)).MakeParallel; // next stage var ATREndPoint := TConverter.CreateEndpoint(ATR.Sender, 5); var ATRSeries: TSeries; var HullEndPoint := TConverter.CreateEndpoint(Hull.Sender, 5); var HullSeries: TSeries; var SmaEndPoint := TConverter.CreateEndpoint(Sma.Sender, 5); var SmaSeries: TSeries; var curr: TSignal; curr.SL := Double.NaN; curr.Entry := Double.NaN; var lastHull, lastSma: Double; var conv := TConverter.Join( [Ohlc.Field('Low').Sender, Ohlc.Field('High').Sender, Closes.Sender, ATR.Sender, Hull.Sender, Sma.Sender] ); var Signal := TConverter, TSignal>.CreateGeneric( function(const Values: TArray): 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('pnl'); var FEquity: Double := 10000; var FInit: Boolean := false; var equity := TConverter.CreateAggregation( function(const Value: Double; const Broadcast: TConverter.TBroadcastProc): TState begin if not FInit then begin FInit := true; Broadcast(FEquity); end; if not IsNan(Value) then begin FEquity := FEquity + Value; Result := Broadcast(FEquity); end; end ); pnl.Sender.Link(equity); Result := TConverter, Double>.Construct(ticker, equity.Sender); end; end.