New Test-Startegy
This commit is contained in:
@@ -4,7 +4,7 @@
|
|||||||
<ProjectVersion>20.3</ProjectVersion>
|
<ProjectVersion>20.3</ProjectVersion>
|
||||||
<FrameworkType>FMX</FrameworkType>
|
<FrameworkType>FMX</FrameworkType>
|
||||||
<Base>True</Base>
|
<Base>True</Base>
|
||||||
<Config Condition="'$(Config)'==''">Debug</Config>
|
<Config Condition="'$(Config)'==''">Release</Config>
|
||||||
<Platform Condition="'$(Platform)'==''">Win64</Platform>
|
<Platform Condition="'$(Platform)'==''">Win64</Platform>
|
||||||
<ProjectName Condition="'$(ProjectName)'==''">AuraTrader</ProjectName>
|
<ProjectName Condition="'$(ProjectName)'==''">AuraTrader</ProjectName>
|
||||||
<TargetedPlatforms>3</TargetedPlatforms>
|
<TargetedPlatforms>3</TargetedPlatforms>
|
||||||
|
|||||||
+57
-41
@@ -52,7 +52,8 @@ uses
|
|||||||
DynamicFMXControl,
|
DynamicFMXControl,
|
||||||
Myc.FMX.Chart,
|
Myc.FMX.Chart,
|
||||||
Myc.Trade.Indicators,
|
Myc.Trade.Indicators,
|
||||||
Myc.DataRecord;
|
Myc.DataRecord,
|
||||||
|
StrategyTest;
|
||||||
|
|
||||||
type
|
type
|
||||||
TForm1 = class(TForm)
|
TForm1 = class(TForm)
|
||||||
@@ -117,16 +118,6 @@ type
|
|||||||
property OnEvent: TNotifyEvent read FOnEvent write FOnEvent;
|
property OnEvent: TNotifyEvent read FOnEvent write FOnEvent;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
TEquitySum = class(TMycConverter<Double, Double>)
|
|
||||||
private
|
|
||||||
FEquity: Double;
|
|
||||||
FInit: Boolean;
|
|
||||||
protected
|
|
||||||
function ProcessData(const Value: Double): TState; override;
|
|
||||||
public
|
|
||||||
constructor Create(AEquity: Double);
|
|
||||||
end;
|
|
||||||
|
|
||||||
var
|
var
|
||||||
Form1: TForm1;
|
Form1: TForm1;
|
||||||
|
|
||||||
@@ -426,7 +417,28 @@ begin
|
|||||||
|
|
||||||
var pnl := Signal.Field<Double>('pnl');
|
var pnl := Signal.Field<Double>('pnl');
|
||||||
|
|
||||||
var equity: TConverter<Double, Double> := TEquitySum.Create(10000);
|
var FEquity: Double;
|
||||||
|
var FInit: Boolean;
|
||||||
|
|
||||||
|
var equity :=
|
||||||
|
TConverter<Double, Double>.CreateAggregation(
|
||||||
|
function(const Value: Double; const Broadcast: TConverter<Double, Double>.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
|
||||||
|
);
|
||||||
|
|
||||||
|
// var equity: TConverter<Double, Double> := TEquitySum.Create(10000);
|
||||||
pnl.Sender.Link(equity);
|
pnl.Sender.Link(equity);
|
||||||
|
|
||||||
var Layout := CurrLayout<TVertScrollBox>;
|
var Layout := CurrLayout<TVertScrollBox>;
|
||||||
@@ -635,7 +647,27 @@ begin
|
|||||||
|
|
||||||
var pnl := Signal.Field<Double>('pnl');
|
var pnl := Signal.Field<Double>('pnl');
|
||||||
|
|
||||||
var equity: TConverter<Double, Double> := TEquitySum.Create(10000);
|
var FEquity: Double := 10000;
|
||||||
|
var FInit: Boolean := false;
|
||||||
|
|
||||||
|
var equity :=
|
||||||
|
TConverter<Double, Double>.CreateAggregation(
|
||||||
|
function(const Value: Double; const Broadcast: TConverter<Double, Double>.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);
|
pnl.Sender.Link(equity);
|
||||||
|
|
||||||
var Layout := CurrLayout<TVertScrollBox>;
|
var Layout := CurrLayout<TVertScrollBox>;
|
||||||
@@ -867,38 +899,22 @@ begin
|
|||||||
var timeframe := TTimeframe.M15;
|
var timeframe := TTimeframe.M15;
|
||||||
ExecuteStrategy(Symbol, timeframe, CreateStrategy2(timeframe));
|
ExecuteStrategy(Symbol, timeframe, CreateStrategy2(timeframe));
|
||||||
|
|
||||||
// timeframe := M5;
|
var tstStrat := StrategyTest.CreateStrategy1(timeframe);
|
||||||
// ExecuteStrategy(Symbol, timeframe, CreateStrategy2(timeframe));
|
ExecuteStrategy(Symbol, timeframe, tstStrat);
|
||||||
// timeframe := H4;
|
|
||||||
// ExecuteStrategy(Symbol, timeframe, CreateStrategy2(timeframe));
|
|
||||||
// timeframe := D;
|
|
||||||
// ExecuteStrategy(Symbol, timeframe, CreateStrategy2(timeframe));
|
|
||||||
// timeframe := M;
|
|
||||||
// ExecuteStrategy(Symbol, timeframe, CreateStrategy2(timeframe));
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ TEquitySum<S, T> }
|
var Layout := CurrLayout<TVertScrollBox>;
|
||||||
|
if Layout = nil then
|
||||||
|
exit;
|
||||||
|
|
||||||
constructor TEquitySum.Create(AEquity: Double);
|
var pnlChart := TMycChart.Create(Self);
|
||||||
begin
|
AlignControl(pnlChart);
|
||||||
inherited Create;
|
pnlChart.Height := Layout.ChildrenRect.Width * 9 / 24;
|
||||||
FEquity := AEquity;
|
pnlChart.Lookback.Value := 50000;
|
||||||
FInit := false;
|
|
||||||
end;
|
|
||||||
|
|
||||||
function TEquitySum.ProcessData(const Value: Double): TState;
|
pnlChart.SetXAxisCounter<Double>(tstStrat.Sender);
|
||||||
begin
|
|
||||||
if not FInit then
|
|
||||||
begin
|
|
||||||
FInit := true;
|
|
||||||
Broadcast(FEquity);
|
|
||||||
end;
|
|
||||||
|
|
||||||
if not IsNan(Value) then
|
var panel := pnlChart.AddPanel;
|
||||||
begin
|
panel.AddDoubleSeries(tstStrat.Sender, TAlphaColors.Blue, 3);
|
||||||
FEquity := FEquity + Value;
|
|
||||||
Result := Broadcast(FEquity);
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|||||||
@@ -0,0 +1,190 @@
|
|||||||
|
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<TDataPoint<TOhlcItem>, Double>;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
uses
|
||||||
|
System.SysUtils,
|
||||||
|
System.Math;
|
||||||
|
|
||||||
|
function CreateStrategy1(Timeframe: TTimeframe): TConverter<TDataPoint<TOhlcItem>, Double>;
|
||||||
|
type
|
||||||
|
TSignal = record
|
||||||
|
Sig: Double;
|
||||||
|
SL: Double;
|
||||||
|
Entry: Double;
|
||||||
|
pnl: Double;
|
||||||
|
end;
|
||||||
|
begin
|
||||||
|
var ticker := TConverter.CreateIdentity<TDataPoint<TOhlcItem>>;
|
||||||
|
|
||||||
|
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 FEquity: Double := 10000;
|
||||||
|
var FInit: Boolean := false;
|
||||||
|
|
||||||
|
var equity :=
|
||||||
|
TConverter<Double, Double>.CreateAggregation(
|
||||||
|
function(const Value: Double; const Broadcast: TConverter<Double, Double>.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<TDataPoint<TOhlcItem>, Double>.Construct(ticker, equity.Sender);
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
||||||
@@ -89,6 +89,15 @@ type
|
|||||||
constructor Create(const AFunc: TConstFunc<S, T>);
|
constructor Create(const AFunc: TConstFunc<S, T>);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
TMycGenericAggregator<S, T> = class(TMycConverter<S, T>)
|
||||||
|
private
|
||||||
|
FFunc: TConstFunc<S, TConverter<S, T>.TBroadcastProc, TState>;
|
||||||
|
protected
|
||||||
|
function ProcessData(const Value: S): TState; override;
|
||||||
|
public
|
||||||
|
constructor Create(const AFunc: TConstFunc<S, TConverter<S, T>.TBroadcastProc, TState>);
|
||||||
|
end;
|
||||||
|
|
||||||
TMycGenericParallelConverter<S, T> = class(TMycConverter<S, T>)
|
TMycGenericParallelConverter<S, T> = class(TMycConverter<S, T>)
|
||||||
private
|
private
|
||||||
FFunc: TConstFunc<S, T>;
|
FFunc: TConstFunc<S, T>;
|
||||||
@@ -235,6 +244,17 @@ type
|
|||||||
property Sender: TMycContainedDataProvider<TArray<T>> read FSender implements TDataProvider<TArray<T>>.IDataProvider;
|
property Sender: TMycContainedDataProvider<TArray<T>> read FSender implements TDataProvider<TArray<T>>.IDataProvider;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
TMycComposedConverter<S, T> = class(TMycProcessor<S>, TConverter<S, T>.IConverter)
|
||||||
|
private
|
||||||
|
FProcessor: IMycProcessor<S>;
|
||||||
|
FDataProvider: TDataProvider<T>;
|
||||||
|
protected
|
||||||
|
function ProcessData(const Value: S): TState; override;
|
||||||
|
function GetSender: TDataProvider<T>.IDataProvider;
|
||||||
|
public
|
||||||
|
constructor Create(const AProcessor: IMycProcessor<S>; const ADataProvider: TDataProvider<T>);
|
||||||
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
uses
|
uses
|
||||||
@@ -892,4 +912,32 @@ begin
|
|||||||
FSender.Broadcast(Arr);
|
FSender.Broadcast(Arr);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
constructor TMycGenericAggregator<S, T>.Create(const AFunc: TConstFunc<S, TConverter<S, T>.TBroadcastProc, TState>);
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
FFunc := AFunc;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TMycGenericAggregator<S, T>.ProcessData(const Value: S): TState;
|
||||||
|
begin
|
||||||
|
Result := FFunc(Value, function(const Value: T): TState begin Result := FSender.Broadcast(Value); end);
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TMycComposedConverter<S, T>.Create(const AProcessor: IMycProcessor<S>; const ADataProvider: TDataProvider<T>);
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
FProcessor := AProcessor;
|
||||||
|
FDataProvider := ADataProvider;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TMycComposedConverter<S, T>.GetSender: TDataProvider<T>.IDataProvider;
|
||||||
|
begin
|
||||||
|
Result := FDataProvider;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TMycComposedConverter<S, T>.ProcessData(const Value: S): TState;
|
||||||
|
begin
|
||||||
|
Result := FProcessor.ProcessData(Value);
|
||||||
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|||||||
@@ -67,6 +67,8 @@ type
|
|||||||
property Sender: TDataProvider<T>.IDataProvider read GetSender;
|
property Sender: TDataProvider<T>.IDataProvider read GetSender;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
TBroadcastProc = reference to function(const Value: T): TState;
|
||||||
|
|
||||||
strict private
|
strict private
|
||||||
class var
|
class var
|
||||||
FNull: IConverter;
|
FNull: IConverter;
|
||||||
@@ -82,7 +84,9 @@ type
|
|||||||
class operator Implicit(const A: IConverter): TConverter<S, T>; overload;
|
class operator Implicit(const A: IConverter): TConverter<S, T>; overload;
|
||||||
class operator Implicit(const A: TConverter<S, T>): IConverter; overload;
|
class operator Implicit(const A: TConverter<S, T>): IConverter; overload;
|
||||||
|
|
||||||
|
class function Construct(const Processor: IMycProcessor<S>; const DataProvider: TDataProvider<T>): TConverter<S, T>; static;
|
||||||
class function CreateGeneric(const Func: TConstFunc<S, T>): TConverter<S, T>; static;
|
class function CreateGeneric(const Func: TConstFunc<S, T>): TConverter<S, T>; static;
|
||||||
|
class function CreateAggregation(const Func: TConstFunc<S, TBroadcastProc, TState>): TConverter<S, T>; static;
|
||||||
class function CreateParallel(const Func: TConstFunc<S, T>): TConverter<S, T>; static;
|
class function CreateParallel(const Func: TConstFunc<S, T>): TConverter<S, T>; static;
|
||||||
|
|
||||||
function Chain<R>(const Next: TConverter<T, R>): TConverter<T, R>; overload; inline;
|
function Chain<R>(const Next: TConverter<T, R>): TConverter<T, R>; overload; inline;
|
||||||
@@ -221,6 +225,16 @@ begin
|
|||||||
Result := Chain<R>(TMycGenericParallelConverter<T, R>.Create(Func));
|
Result := Chain<R>(TMycGenericParallelConverter<T, R>.Create(Func));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
class function TConverter<S, T>.Construct(const Processor: IMycProcessor<S>; const DataProvider: TDataProvider<T>): TConverter<S, T>;
|
||||||
|
begin
|
||||||
|
Result := TMycComposedConverter<S, T>.Create(Processor, DataProvider);
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TConverter<S, T>.CreateAggregation(const Func: TConstFunc<S, TBroadcastProc, TState>): TConverter<S, T>;
|
||||||
|
begin
|
||||||
|
Result := TMycGenericAggregator<S, T>.Create(Func);
|
||||||
|
end;
|
||||||
|
|
||||||
class function TConverter<S, T>.CreateGeneric(const Func: TConstFunc<S, T>): TConverter<S, T>;
|
class function TConverter<S, T>.CreateGeneric(const Func: TConstFunc<S, T>): TConverter<S, T>;
|
||||||
begin
|
begin
|
||||||
Result := TMycGenericConverter<S, T>.Create(Func);
|
Result := TMycGenericConverter<S, T>.Create(Func);
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ type
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
TConstFunc<S, T> = reference to function(const Value: S): T;
|
TConstFunc<S, T> = reference to function(const Value: S): T;
|
||||||
|
TConstFunc<S, T, U> = reference to function(const Value1: S; const Value2: T): U;
|
||||||
TConstProc<T> = reference to procedure(const Value: T);
|
TConstProc<T> = reference to procedure(const Value: T);
|
||||||
TConstFuncPredicate<S, T> = reference to function(const Value: S; out Res: T): Boolean;
|
TConstFuncPredicate<S, T> = reference to function(const Value: S; out Res: T): Boolean;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user