Work in Progress
This commit is contained in:
@@ -9,7 +9,6 @@ uses
|
||||
Myc.Aura.Parameter in '..\Src\Myc.Aura.Parameter.pas',
|
||||
TestModule in 'TestModule.pas',
|
||||
DynamicFMXControl in 'DynamicFMXControl.pas',
|
||||
FirstStrategy in 'FirstStrategy.pas',
|
||||
Myc.Trade.DataArray in '..\Src\Myc.Trade.DataArray.pas',
|
||||
Myc.FMX.Chart.Series in '..\Src\Myc.FMX.Chart.Series.pas',
|
||||
Myc.Trade.Indicators in '..\Src\Myc.Trade.Indicators.pas',
|
||||
|
||||
@@ -137,7 +137,6 @@
|
||||
<DCCReference Include="..\Src\Myc.Aura.Parameter.pas"/>
|
||||
<DCCReference Include="TestModule.pas"/>
|
||||
<DCCReference Include="DynamicFMXControl.pas"/>
|
||||
<DCCReference Include="FirstStrategy.pas"/>
|
||||
<DCCReference Include="..\Src\Myc.Trade.DataArray.pas"/>
|
||||
<DCCReference Include="..\Src\Myc.FMX.Chart.Series.pas"/>
|
||||
<DCCReference Include="..\Src\Myc.Trade.Indicators.pas"/>
|
||||
|
||||
@@ -1,141 +0,0 @@
|
||||
unit FirstStrategy;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
System.SysUtils,
|
||||
System.Generics.Collections,
|
||||
Myc.Signals,
|
||||
Myc.Mutable,
|
||||
Myc.TaskManager,
|
||||
Myc.Trade.Types,
|
||||
Myc.Trade.DataPoint,
|
||||
Myc.Trade.DataArray,
|
||||
Myc.Trade.DataPoint.Impl;
|
||||
|
||||
type
|
||||
TTickAggregation = class(TMycConverter<TDataPoint<Double>, TDataPoint<TOhlcItem>>)
|
||||
private
|
||||
FTimeframe: TTimeframe;
|
||||
FCurrentBar: TDataPoint<TOhlcItem>;
|
||||
function GetBarStartTime(const TimeStamp: TDateTime; const Timeframe: TTimeframe): TDateTime;
|
||||
function GetCurrentBar: TDataPoint<TOhlcItem>;
|
||||
function GetTimeframe: TTimeframe;
|
||||
public
|
||||
constructor Create(const ATimeframe: TTimeframe);
|
||||
function ProcessData(const Value: TDataPoint<Double>): TState; override;
|
||||
property CurrentBar: TDataPoint<TOhlcItem> read GetCurrentBar;
|
||||
property Timeframe: TTimeframe read GetTimeframe;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
System.DateUtils,
|
||||
System.Math;
|
||||
|
||||
{ TTickAggregation }
|
||||
|
||||
constructor TTickAggregation.Create(const ATimeframe: TTimeframe);
|
||||
begin
|
||||
inherited Create;
|
||||
FTimeframe := ATimeframe;
|
||||
end;
|
||||
|
||||
function TTickAggregation.GetBarStartTime(const TimeStamp: TDateTime; const Timeframe: TTimeframe): TDateTime;
|
||||
var
|
||||
baseTime: TDateTime;
|
||||
begin
|
||||
// Align the time grid to UTC 0:00 using functions from System.DateUtils
|
||||
baseTime := RecodeMilliSecond(TimeStamp, 0);
|
||||
|
||||
case Timeframe of
|
||||
S: Result := baseTime;
|
||||
S5: Result := RecodeSecond(baseTime, SecondOf(TimeStamp) - (SecondOf(TimeStamp) mod 5));
|
||||
S15: Result := RecodeSecond(baseTime, SecondOf(TimeStamp) - (SecondOf(TimeStamp) mod 15));
|
||||
S30: Result := RecodeSecond(baseTime, SecondOf(TimeStamp) - (SecondOf(TimeStamp) mod 30));
|
||||
|
||||
M: Result := RecodeSecond(baseTime, 0);
|
||||
M2: Result := RecodeMinute(RecodeSecond(baseTime, 0), MinuteOf(TimeStamp) - (MinuteOf(TimeStamp) mod 2));
|
||||
M3: Result := RecodeMinute(RecodeSecond(baseTime, 0), MinuteOf(TimeStamp) - (MinuteOf(TimeStamp) mod 3));
|
||||
M5: Result := RecodeMinute(RecodeSecond(baseTime, 0), MinuteOf(TimeStamp) - (MinuteOf(TimeStamp) mod 5));
|
||||
M10: Result := RecodeMinute(RecodeSecond(baseTime, 0), MinuteOf(TimeStamp) - (MinuteOf(TimeStamp) mod 10));
|
||||
M15: Result := RecodeMinute(RecodeSecond(baseTime, 0), MinuteOf(TimeStamp) - (MinuteOf(TimeStamp) mod 15));
|
||||
M30: Result := RecodeMinute(RecodeSecond(baseTime, 0), MinuteOf(TimeStamp) - (MinuteOf(TimeStamp) mod 30));
|
||||
|
||||
H: Result := RecodeMinute(RecodeSecond(baseTime, 0), 0);
|
||||
H2: Result := RecodeHour(RecodeMinute(RecodeSecond(baseTime, 0), 0), HourOf(TimeStamp) - (HourOf(TimeStamp) mod 2));
|
||||
H3: Result := RecodeHour(RecodeMinute(RecodeSecond(baseTime, 0), 0), HourOf(TimeStamp) - (HourOf(TimeStamp) mod 3));
|
||||
H4: Result := RecodeHour(RecodeMinute(RecodeSecond(baseTime, 0), 0), HourOf(TimeStamp) - (HourOf(TimeStamp) mod 4));
|
||||
H8: Result := RecodeHour(RecodeMinute(RecodeSecond(baseTime, 0), 0), HourOf(TimeStamp) - (HourOf(TimeStamp) mod 8));
|
||||
H12: Result := RecodeHour(RecodeMinute(RecodeSecond(baseTime, 0), 0), HourOf(TimeStamp) - (HourOf(TimeStamp) mod 12));
|
||||
|
||||
D: Result := StartOfTheDay(TimeStamp);
|
||||
// D2, D3 are uncommon; this is a simple modulo-based approach relative to TDateTime's epoch.
|
||||
D2: Result := Floor(TimeStamp) - (Floor(TimeStamp) mod 2);
|
||||
D3: Result := Floor(TimeStamp) - (Floor(TimeStamp) mod 3);
|
||||
|
||||
W: Result := TimeStamp.StartOfTheWeek;
|
||||
|
||||
MN: Result := TimeStamp.StartOfTheMonth;
|
||||
// Quarter alignment
|
||||
MN3: Result := RecodeMonth(TimeStamp.StartOfTheMonth, (MonthOf(TimeStamp) - 1) div 3 * 3 + 1);
|
||||
// Half-year alignment
|
||||
MN6: Result := RecodeMonth(TimeStamp.StartOfTheMonth, (MonthOf(TimeStamp) - 1) div 6 * 6 + 1);
|
||||
|
||||
Y: Result := TimeStamp.StartOfTheYear;
|
||||
else
|
||||
// Fallback for any undefined timeframe
|
||||
Result := 0;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TTickAggregation.GetCurrentBar: TDataPoint<TOhlcItem>;
|
||||
begin
|
||||
Result := FCurrentBar;
|
||||
end;
|
||||
|
||||
function TTickAggregation.GetTimeframe: TTimeframe;
|
||||
begin
|
||||
Result := FTimeframe;
|
||||
end;
|
||||
|
||||
function TTickAggregation.ProcessData(const Value: TDataPoint<Double>): TState;
|
||||
var
|
||||
barStartTime: TDateTime;
|
||||
lastBarTime: TDateTime;
|
||||
begin
|
||||
// Update bar for the strategy's timeframe
|
||||
barStartTime := GetBarStartTime(Value.Time, FTimeframe);
|
||||
lastBarTime := FCurrentBar.Time;
|
||||
|
||||
if (barStartTime > lastBarTime) then
|
||||
begin
|
||||
// A new bar starts, so the previous one is now complete.
|
||||
if (lastBarTime > 0) then
|
||||
begin
|
||||
Result := Broadcast(FCurrentBar);
|
||||
end;
|
||||
|
||||
// Start a new bar, Volume is 1 because this is the first tick.
|
||||
FCurrentBar.Data.Open := Value.Data;
|
||||
FCurrentBar.Data.High := Value.Data;
|
||||
FCurrentBar.Data.Low := Value.Data;
|
||||
FCurrentBar.Data.Close := Value.Data;
|
||||
FCurrentBar.Data.Volume := 1;
|
||||
FCurrentBar.Time := barStartTime;
|
||||
end
|
||||
else
|
||||
begin
|
||||
// Update the currently aggregating bar
|
||||
if Value.Data > FCurrentBar.Data.High then
|
||||
FCurrentBar.Data.High := Value.Data;
|
||||
if Value.Data < FCurrentBar.Data.Low then
|
||||
FCurrentBar.Data.Low := Value.Data;
|
||||
FCurrentBar.Data.Close := Value.Data;
|
||||
// Volume is the number of ticks needed to build the complete bar.
|
||||
FCurrentBar.Data.Volume := FCurrentBar.Data.Volume + 1;
|
||||
end;
|
||||
end;
|
||||
|
||||
end.
|
||||
+165
-143
@@ -11,6 +11,7 @@ uses
|
||||
System.DateUtils,
|
||||
System.Generics.Collections,
|
||||
System.Rtti,
|
||||
System.Math,
|
||||
FMX.Types,
|
||||
FMX.Controls,
|
||||
FMX.Forms,
|
||||
@@ -32,9 +33,11 @@ uses
|
||||
Myc.Trade.DataPoint,
|
||||
Myc.Signals,
|
||||
Myc.Mutable,
|
||||
Myc.Trade.DataArray,
|
||||
Myc.Signals.FMX,
|
||||
Myc.TaskManager,
|
||||
Myc.Aura.Module,
|
||||
Myc.Trade.DataPoint.Impl,
|
||||
FMX.ListBox,
|
||||
FMX.Layouts,
|
||||
FMX.TreeView,
|
||||
@@ -45,7 +48,6 @@ uses
|
||||
System.Actions,
|
||||
FMX.ActnList,
|
||||
DynamicFMXControl,
|
||||
FirstStrategy,
|
||||
Myc.FMX.Chart;
|
||||
|
||||
type
|
||||
@@ -103,6 +105,15 @@ type
|
||||
property OnEvent: TNotifyEvent read FOnEvent write FOnEvent;
|
||||
end;
|
||||
|
||||
TEquitySum = class(TMycConverter<Double, Double>)
|
||||
private
|
||||
FEquity: Double;
|
||||
protected
|
||||
function ProcessData(const Value: Double): TState; override;
|
||||
public
|
||||
constructor Create(AEquity: Double);
|
||||
end;
|
||||
|
||||
var
|
||||
Form1: TForm1;
|
||||
|
||||
@@ -343,7 +354,7 @@ begin
|
||||
end
|
||||
);
|
||||
|
||||
var OhlcPoint := lastPrice.Chain<TDataPoint<TOhlcItem>>(TTickAggregation.Create(timeframe));
|
||||
var OhlcPoint := lastPrice.Chain<TDataPoint<TOhlcItem>>(TConverter.CreateAggregation(timeframe));
|
||||
|
||||
var Timestamps := OhlcPoint.Field<TDateTime>('Time');
|
||||
var Ohlc := OhlcPoint.Field<TOhlcItem>('Data');
|
||||
@@ -410,6 +421,13 @@ begin
|
||||
end;
|
||||
|
||||
procedure TForm1.Strat2ButtonClick(Sender: TObject);
|
||||
type
|
||||
TSignal = record
|
||||
Sig: Double;
|
||||
SL: Double;
|
||||
Entry: Double;
|
||||
pnl: Double;
|
||||
end;
|
||||
begin
|
||||
var timeframe := TTimeframe.M15;
|
||||
|
||||
@@ -417,26 +435,123 @@ begin
|
||||
|
||||
var lastPrice :=
|
||||
ticker.Chain<TDataPoint<Double>>(
|
||||
function(const Tick: TDataPoint<TAskBidItem>): TDataPoint<Double>
|
||||
begin
|
||||
Result.Time := Tick.Time;
|
||||
Result.Data := 0.5 * (Tick.Data.Ask + Tick.Data.Bid);
|
||||
end
|
||||
TConverter.CreateDataPointConverter<TAskBidItem, Double>(
|
||||
function(const Tick: TAskBidItem): Double begin Result := 0.5 * (Tick.Ask + Tick.Bid); end
|
||||
)
|
||||
);
|
||||
|
||||
var OhlcPoint := TTickAggregation.Create(timeframe);
|
||||
lastPrice.Sender.Link(OhlcPoint);
|
||||
var OhlcPoint := lastPrice.Chain<TDataPoint<TOhlcItem>>(TConverter.CreateAggregation(timeframe));
|
||||
|
||||
var Closes :=
|
||||
TConverter<TDataPoint<TOhlcItem>, Double>
|
||||
.CreateGeneric(function(const Ohlc: TDataPoint<TOhlcItem>): Double begin Result := Ohlc.Data.Close; end);
|
||||
var Ohlc := TConverter.CreateSequence<TOhlcItem>(2, OhlcPoint.Field<TOhlcItem>('Data').Sender);
|
||||
|
||||
var Hull := TConverter<Double, Double>.CreateGeneric(TIndicators.CreateHMA(150));
|
||||
var Closes := Ohlc[0].Field<Double>('Close');
|
||||
|
||||
var Timestamps :=
|
||||
TConverter<TDataPoint<TOhlcItem>, TDateTime>
|
||||
.CreateGeneric(function(const Ohlc: TDataPoint<TOhlcItem>): TDateTime begin Result := Ohlc.Time; end);
|
||||
OhlcPoint.Sender.Link(TimeStamps);
|
||||
var Hull := Closes.Chain<Double>(TIndicators.CreateHMA(250));
|
||||
var Sma := Closes.Chain<Double>(TIndicators.CreateSMA(200));
|
||||
|
||||
var HullSeries := TConverter.CreateEndpoint<Double>(Hull.Sender, 5);
|
||||
var SmaSeries := TConverter.CreateEndpoint<Double>(Sma.Sender, 5);
|
||||
|
||||
var Lowest: Double := Double.MaxValue;
|
||||
var Highest: Double := Double.MinValue;
|
||||
|
||||
var curr: TSignal;
|
||||
curr.SL := Double.NaN;
|
||||
curr.Entry := Double.NaN;
|
||||
|
||||
var ATR := Ohlc[0].Chain<Double>(TIndicators.CreateATR(50));
|
||||
var ATRSeries := TConverter.CreateEndpoint<Double>(ATR.Sender, 5);
|
||||
|
||||
// next stage
|
||||
|
||||
var Signal :=
|
||||
Ohlc[1]
|
||||
.Chain<TSignal>(
|
||||
function(const Ohlc: TOhlcItem): TSignal
|
||||
begin
|
||||
var pnl: Double := 0;
|
||||
|
||||
if Ohlc.Low < Lowest then
|
||||
Lowest := Ohlc.Low;
|
||||
if Ohlc.High > Highest then
|
||||
Highest := Ohlc.High;
|
||||
|
||||
Result := curr;
|
||||
Result.Sig := 0;
|
||||
pnl := NaN;
|
||||
|
||||
if (HullSeries.Value[0] < SmaSeries.Value[0]) and (HullSeries.Value[1] >= SmaSeries.Value[1]) then
|
||||
begin
|
||||
if curr.Sig > 0 then
|
||||
pnl := Ohlc.Close - curr.Entry;
|
||||
|
||||
curr.Sig := -1;
|
||||
curr.SL := Highest;
|
||||
curr.Entry := Ohlc.Close;
|
||||
Result := curr;
|
||||
end
|
||||
else if (HullSeries.Value[0] > SmaSeries.Value[0]) and (HullSeries.Value[1] <= SmaSeries.Value[1]) then
|
||||
begin
|
||||
if curr.Sig < 0 then
|
||||
pnl := curr.Entry - Ohlc.Close;
|
||||
|
||||
curr.Sig := 1;
|
||||
curr.SL := Lowest;
|
||||
curr.Entry := Ohlc.Close;
|
||||
Result := curr;
|
||||
end;
|
||||
|
||||
var atr := 15 * ATRSeries.Value[0];
|
||||
if curr.Sig > 0 then
|
||||
begin
|
||||
if Ohlc.Close > curr.SL then
|
||||
begin
|
||||
if curr.SL < Ohlc.Close - atr then
|
||||
curr.SL := Ohlc.Close - atr;
|
||||
Result.SL := curr.SL;
|
||||
end;
|
||||
|
||||
if Ohlc.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 Ohlc.Close < curr.SL then
|
||||
begin
|
||||
if curr.SL > Ohlc.Close + atr then
|
||||
curr.SL := Ohlc.Close + atr;
|
||||
Result.SL := curr.SL;
|
||||
end;
|
||||
|
||||
if Ohlc.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;
|
||||
end);
|
||||
|
||||
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
|
||||
@@ -451,142 +566,49 @@ begin
|
||||
chart.Height := Layout.ChildrenRect.Width * 9 / 16;
|
||||
chart.Lookback.Value := 50000;
|
||||
|
||||
/////
|
||||
chart.SetXAxisSeries(M15, OhlcPoint.Field<TDateTime>('Time').Sender);
|
||||
|
||||
{
|
||||
var panel := chart.AddPanel;
|
||||
panel.AddOhlcSeries(Ohlc[0].Sender);
|
||||
panel.AddDoubleSeries(Hull.Sender, TAlphaColors.Cornflowerblue, 2);
|
||||
panel.AddDoubleSeries(Sma.Sender, TAlphaColors.Brown, 1.5);
|
||||
panel.AddDoubleSeries(Signal.Field<Double>('SL').Sender, TAlphaColors.Red, 2);
|
||||
panel.AddDoubleSeries(Signal.Field<Double>('Entry').Sender, TAlphaColors.Green, 1);
|
||||
|
||||
chart.SetXAxisSeries(timeframe, Timestamps.Sender);
|
||||
// panel := chart.AddPanel;
|
||||
// panel.AddDoubleSeries( equity.Sender, TAlphaColors.Blue, 3 );
|
||||
|
||||
var Panel := chart.AddPanel;
|
||||
var pnlChart := TMycChart.Create(Self);
|
||||
AlignControl(pnlChart);
|
||||
pnlChart.Height := Layout.ChildrenRect.Width * 9 / 24;
|
||||
pnlChart.Lookback.Value := 50000;
|
||||
|
||||
pnlChart.SetXAxisCounter<Double>(equity.Sender);
|
||||
|
||||
OhlcPoint.Sender.Link(Ohlc);
|
||||
Panel.AddOhlcSeries(Ohlc.Sender);
|
||||
|
||||
Ohlc.Sender.Link(Closes);
|
||||
|
||||
var Hull: IMycConverter<Double, Double> := TGenericIndicator<Double, Double>.Create(TIndicators.CreateHMA(150));
|
||||
Closes.Sender.Link(Hull);
|
||||
Panel.AddDoubleSeries(Hull.Sender, TAlphaColors.Aliceblue);
|
||||
|
||||
// Add SMA (Simple Moving Average)
|
||||
var Sma: IMycConverter<Double, Double> := TGenericIndicator<Double, Double>.Create(TIndicators.CreateSMA(50));
|
||||
Closes.Sender.Link(Sma);
|
||||
Panel.AddDoubleSeries(Sma.Sender, TAlphaColors.Yellow);
|
||||
|
||||
// Add EMA (Exponential Moving Average)
|
||||
var Ema: IMycConverter<Double, Double> := TGenericIndicator<Double, Double>.Create(TIndicators.CreateEMA(21));
|
||||
Closes.Sender.Link(Ema);
|
||||
Panel.AddDoubleSeries(Ema.Sender, TAlphaColors.Aqua);
|
||||
|
||||
// Add Bollinger Bands (20, 2.0)
|
||||
var Boli: IMycConverter<Double, TBollingerBandsResult> :=
|
||||
TGenericIndicator<Double, TBollingerBandsResult>.Create(TIndicators.CreateBollingerBands(20, 2.0));
|
||||
Closes.Sender.Link(Boli);
|
||||
|
||||
var BoliUpper: IMycConverter<TBollingerBandsResult, Double> :=
|
||||
TMycGenericConverter<TBollingerBandsResult, Double>
|
||||
.Create(function(const Item: TBollingerBandsResult): Double begin Result := Item.UpperBand; end);
|
||||
Boli.Sender.Link(BoliUpper);
|
||||
Panel.AddDoubleSeries(BoliUpper.Sender, TAlphaColors.Gray);
|
||||
|
||||
var BoliMiddle: IMycConverter<TBollingerBandsResult, Double> :=
|
||||
TMycGenericConverter<TBollingerBandsResult, Double>
|
||||
.Create(function(const Item: TBollingerBandsResult): Double begin Result := Item.MiddleBand; end);
|
||||
Boli.Sender.Link(BoliMiddle);
|
||||
Panel.AddDoubleSeries(BoliMiddle.Sender, TAlphaColors.Darkgray, 1.0);
|
||||
|
||||
var BoliLower: IMycConverter<TBollingerBandsResult, Double> :=
|
||||
TMycGenericConverter<TBollingerBandsResult, Double>
|
||||
.Create(function(const Item: TBollingerBandsResult): Double begin Result := Item.LowerBand; end);
|
||||
Boli.Sender.Link(BoliLower);
|
||||
Panel.AddDoubleSeries(BoliLower.Sender, TAlphaColors.Gray);
|
||||
|
||||
Panel := chart.AddPanel;
|
||||
|
||||
// Add RSI (Relative Strength Index)
|
||||
var Rsi: IMycConverter<Double, Double> := TGenericIndicator<Double, Double>.Create(TIndicators.CreateRSI(14));
|
||||
Closes.Sender.Link(Rsi);
|
||||
Panel.AddDoubleSeries(Rsi.Sender, TAlphaColors.Fuchsia);
|
||||
|
||||
// Add MACD (12, 26, 9)
|
||||
var Macd: IMycConverter<Double, TMacdResult> := TGenericIndicator<Double, TMacdResult>.Create(TIndicators.CreateMACD(12, 26, 9));
|
||||
Closes.Sender.Link(Macd);
|
||||
|
||||
Panel := chart.AddPanel;
|
||||
|
||||
var MacdLine: IMycConverter<TMacdResult, Double> :=
|
||||
TMycGenericConverter<TMacdResult, Double>.Create(function(const Item: TMacdResult): Double begin Result := Item.MacdLine; end);
|
||||
Macd.Sender.Link(MacdLine);
|
||||
Panel.AddDoubleSeries(MacdLine.Sender, TAlphaColors.Orange);
|
||||
|
||||
var MacdSignal: IMycConverter<TMacdResult, Double> :=
|
||||
TMycGenericConverter<TMacdResult, Double>.Create(function(const Item: TMacdResult): Double begin Result := Item.SignalLine; end);
|
||||
Macd.Sender.Link(MacdSignal);
|
||||
Panel.AddDoubleSeries(MacdSignal.Sender, TAlphaColors.Dodgerblue);
|
||||
|
||||
var MacdHist: IMycConverter<TMacdResult, Double> :=
|
||||
TMycGenericConverter<TMacdResult, Double>.Create(function(const Item: TMacdResult): Double begin Result := Item.Histogram; end);
|
||||
Macd.Sender.Link(MacdHist);
|
||||
Panel.AddDoubleSeries(MacdHist.Sender, TAlphaColors.Lightgreen, 1.0);
|
||||
|
||||
Panel := chart.AddPanel;
|
||||
|
||||
// Add Stochastic Oscillator (14, 3) - This needs OHLC data, not just Close prices.
|
||||
var Stoch: IMycConverter<TOhlcItem, TStochasticResult> :=
|
||||
TGenericIndicator<TOhlcItem, TStochasticResult>.Create(TIndicators.CreateStochastic(14, 3));
|
||||
Ohlc.Sender.Link(Stoch);
|
||||
|
||||
var StochK: IMycConverter<TStochasticResult, Double> :=
|
||||
TMycGenericConverter<TStochasticResult, Double>.Create(function(const Item: TStochasticResult): Double begin Result := Item.K; end);
|
||||
Stoch.Sender.Link(StochK);
|
||||
Panel.AddDoubleSeries(StochK.Sender, TAlphaColors.Green);
|
||||
|
||||
var StochD: IMycConverter<TStochasticResult, Double> :=
|
||||
TMycGenericConverter<TStochasticResult, Double>.Create(function(const Item: TStochasticResult): Double begin Result := Item.D; end);
|
||||
Stoch.Sender.Link(StochD);
|
||||
Panel.AddDoubleSeries(StochD.Sender, TAlphaColors.Red);
|
||||
|
||||
/////
|
||||
|
||||
var tickChart := TMycChart.Create(Self);
|
||||
tickChart.Height := Layout.ChildrenRect.Width * 9 / 16;
|
||||
AlignControl(tickChart);
|
||||
tickChart.Lookback.Value := 1000000;
|
||||
|
||||
var TickTime: IMycConverter<TDataPoint<TAskBidItem>, TDateTime> :=
|
||||
TMycGenericConverter<TDataPoint<TAskBidItem>, TDateTime>
|
||||
.Create(function(const Tick: TDataPoint<TAskBidItem>): TDateTime begin Result := Tick.Time; end);
|
||||
|
||||
var TickAsk: IMycConverter<TDataPoint<TAskBidItem>, Double> :=
|
||||
TMycGenericConverter<TDataPoint<TAskBidItem>, Double>
|
||||
.Create(function(const Tick: TDataPoint<TAskBidItem>): Double begin Result := Tick.Data.Ask; end);
|
||||
|
||||
var TickBid: IMycConverter<TDataPoint<TAskBidItem>, Double> :=
|
||||
TMycGenericConverter<TDataPoint<TAskBidItem>, Double>
|
||||
.Create(function(const Tick: TDataPoint<TAskBidItem>): Double begin Result := Tick.Data.Bid; end);
|
||||
|
||||
var TickSpread: IMycConverter<TDataPoint<TAskBidItem>, Double> :=
|
||||
TMycGenericConverter<TDataPoint<TAskBidItem>, Double>
|
||||
.Create(function(const Tick: TDataPoint<TAskBidItem>): Double begin Result := Tick.Data.Bid-Tick.Data.Ask; end);
|
||||
|
||||
ticker.Sender.Link( TickTime );
|
||||
ticker.Sender.Link( TickAsk );
|
||||
ticker.Sender.Link( TickBid );
|
||||
ticker.Sender.Link( TickSpread );
|
||||
|
||||
tickChart.SetXAxisSeries( TTimeframe.S, TickTime.Sender );
|
||||
panel := tickChart.AddPanel;
|
||||
panel.AddDoubleSeries(TickAsk.Sender, TAlphaColors.Blue);
|
||||
panel.AddDoubleSeries(TickBid.Sender, TAlphaColors.Red);
|
||||
panel := tickChart.AddPanel;
|
||||
panel.AddDoubleSeries(TickSpread.Sender);
|
||||
panel := pnlChart.AddPanel;
|
||||
panel.AddDoubleSeries(equity.Sender, TAlphaColors.Blue, 3);
|
||||
|
||||
/////
|
||||
|
||||
var done := ExecuteStrategy(Symbol, ticker);
|
||||
FProcessDone := TState.All([FProcessDone, done]);
|
||||
}
|
||||
end;
|
||||
|
||||
{ TEquitySum<S, T> }
|
||||
|
||||
constructor TEquitySum.Create(AEquity: Double);
|
||||
begin
|
||||
inherited Create;
|
||||
FEquity := AEquity;
|
||||
end;
|
||||
|
||||
function TEquitySum.ProcessData(const Value: Double): TState;
|
||||
begin
|
||||
if not IsNan(Value) then
|
||||
begin
|
||||
FEquity := FEquity + Value;
|
||||
Result := Broadcast(FEquity);
|
||||
end;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
Reference in New Issue
Block a user